- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
简短版:有没有办法确定由 .net-Core-2 中的 CookieAuthentication 机制创建的 cookie 的内容
上下文:
我目前正在努力使网站符合 GDPR,这意味着记录我们网站上使用和设置的所有 cookie。我们使用 asp.net core 2 和 Identity 来处理用户登录和注销。问题是所有由身份设置的 cookie 以及如何记录它们。 cookies 1.
这个 cookie 很简单,它包含登录信息、权限等。如果您删除它,您将从我们的网站注销。它对我们的应用程序至关重要,因此无需担心。
问题是下面的cookie(注意,是一个cookie分成三部分)
它由 cookieAuthentication 使用和设置,但实际上似乎没有做任何事情。您可以从浏览器中删除它们,并且仍然可以正常使用该网站。例如进行更改并保存 i,您将不会被强制注销。
这带来了一个问题,因为根据新的 GDPR 法律,如果这些 cookie block 是可选的,用户应该能够停用它们。 (后面的问题)
问题就变成了:我怎样才能知道这个 cookie 做了什么以及它包含什么信息。两者同样重要。
尝试过的方法:我试图通过查看源代码来寻找答案,但项目开发在过去的 2 年里断断续续,因此相当拼凑。我还尝试使用这篇文章解密 cookie How to manually decrypt an ASP.NET Core Authentication cookie?作为指南,但我只用 C# 开发了不到 4 个月,所以我无法让它工作,因为它似乎针对的是较旧/不同版本的 .net-core。
注意!由于这是我在堆栈上提出的第一个问题,我欢迎就如何使我的问题更清晰或对本网站的普通民众更有用提出建议和提示。
编辑_1:好吧,启动文件中确实没有太多配置
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true
});
有一些代码可以通过 Microsoft 启用 OpenId。但是会放在这个 cookie 中吗?
// Configure the OWIN Pipeline to use OpenId Connect Authentication
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = Configuration["ClientId"],
Authority = string.Format(Configuration["AadInstance"],
Configuration["Tenant"]),
PostLogoutRedirectUri = Configuration["PostLogoutRedirectUri"],
ClientSecret = Configuration["ClientSecret"],
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
},
Events = new OpenIdConnectEvents
{
OnAuthenticationFailed = OnAuthenticationFailed,
OnRedirectToIdentityProvider = (context) =>
{
if (context.HttpContext.Request.Query.ContainsKey("domain"))
{
context.ProtocolMessage.DomainHint =
context.HttpContext.Request.Query["domain"];
}
return Task.FromResult(0);
},
OnTokenValidated = OnTokenValidated
}
});
edit_2:删除了 DI 和杂项日志记录,但这基本上是整个文件
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Serialization;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
public class Startup
{
public UserManager<ApplicationUser> UserManager { get; set; }
public SignInManager<ApplicationUser> SignInManager { get; set; }
public IConfigurationRoot Configuration { get; set; }
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Adds a default in-memory implementation of IDistributedCache
services.AddMemoryCache();
services.AddSession();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddIdentity<ApplicationUser, IdentityRole>(o => {
// configure identity options
o.Password.RequireDigit = true;
o.Password.RequireLowercase = true;
o.Password.RequireUppercase = true;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 8;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, options => options.ResourcesPath = "Resources")
.AddDataAnnotationsLocalization()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
// OpenID Connect Authentication Requires Cookie Auth
services.AddAuthentication(options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public async void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
SampleDataInitializer sampleData,
SeedData seedData)
{
app.UseSession();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
try
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
serviceScope.ServiceProvider.GetService<ApplicationDbContext>()
.Database.Migrate();
}
}
catch { }
}
else
{
app.UseExceptionHandler("/Home/Error");
// For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
try
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
serviceScope.ServiceProvider.GetService<ApplicationDbContext>()
.Database.Migrate();
}
}
catch { }
}
app.UseStaticFiles();
app.UseIdentity();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true
});
// Configure the OWIN Pipeline to use OpenId Connect Authentication
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = Configuration["ClientId"],
Authority = string.Format(Configuration["AadInstance"], Configuration["Tenant"]),
PostLogoutRedirectUri = Configuration["PostLogoutRedirectUri"],
ClientSecret = Configuration["ClientSecret"],
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
},
Events = new OpenIdConnectEvents
{
OnAuthenticationFailed = OnAuthenticationFailed,
OnRedirectToIdentityProvider = (context) =>
{
if (context.HttpContext.Request.Query.ContainsKey("domain"))
{
context.ProtocolMessage.DomainHint = context.HttpContext.Request.Query["domain"];
}
return Task.FromResult(0);
},
OnTokenValidated = OnTokenValidated
}
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
await seedData.SeedBuyOutPoliciesForDepartments();
}
private async Task<Task> OnTokenValidated(TokenValidatedContext context)
{
try
{
// Get tenant Id from Claims
var claim = context.Ticket.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid");
if (claim?.Value == null)
{
context.HttpContext.Session.SetError("Not able to access tenant id from claim");
return Task.FromResult(true);
}
var tenantId = claim.Value;
var roleClaims = context.Ticket.Principal.Claims.Where(c => c.Type.ToLower().EndsWith("identity/claims/role")).ToList();
//// Get group claims from logged in user
var groupClaims = context.Ticket.Principal.Claims.Where(c => c.Type.ToLower() == "groups").ToList();
var checkClaim = context.HttpContext.Session.GetString("CheckClaim");
if (!string.IsNullOrEmpty(checkClaim))
{
context.HttpContext.Session.Remove("CheckClaim");
var claimInfo = "";
foreach (var currentUserClaim in context.Ticket.Principal.Claims)
{
claimInfo += $"Type: {currentUserClaim.Type} Value: {currentUserClaim.Value} <br/>";
}
// Add groups to claimInfo string
claimInfo += "<br/>Groups: <br/>";
foreach (var groupClaim in groupClaims)
{
claimInfo += $"{groupClaim.Value}, ";
}
// Add role(s) to claimInfo string
claimInfo += "<br />Roles: <br />";
foreach (var roleClaim in roleClaims)
{
claimInfo += $"{roleClaim.Value}, ";
}
context.HttpContext.Session.SetString("Claim", claimInfo);
return Task.FromResult(true);
}
var applicationDbContext = context.HttpContext.RequestServices.GetService<ApplicationDbContext>();
// Check that tenant id exist in database
var customer = applicationDbContext.Customers.Include(c => c.Departments).FirstOrDefault(x => x.TenantId == tenantId);
if (customer == null)
{
context.HttpContext.Session.SetError("Your company is not configured to use log in with work account");
return Task.FromResult(true);
}
// Used to find user in database or create new user
var userManager = context.HttpContext.RequestServices.GetService<UserManager<ApplicationUser>>();
//// Used to update user role
var roleManager = context.HttpContext.RequestServices.GetService<RoleManager<IdentityRole>>();
// Get email adress from AD user
var email = context.Ticket.Principal.Identity.Name;
// Check if user exist in database
var user = await applicationDbContext.Users.Include(u => u.Department).FirstOrDefaultAsync(u => u.Email == email);
if (user == null)
{
if (!customer.AllowCreateUserOnSignIn)
{
context.HttpContext.Session.SetError(
"Your user does not exist in the portal and your company is not configured to allow creation of user on sign in. Please contact your administrator.", customer.ErrorText);
return Task.FromResult(true);
}
// Create new user with AdUser property set to true
var givenName =
context.Ticket.Principal.Claims.FirstOrDefault(
x => x.Type.ToLower().Contains("givenname"));
var surName =
context.Ticket.Principal.Claims.FirstOrDefault(
x => x.Type.ToLower().Contains("surname"));
user = new ApplicationUser
{
AdUser = true,
UserName = email,
Email = email,
FirstName = givenName != null ? givenName.Value : "",
LastName = surName != null ? surName.Value : "",
};
if (user.DepartmentId == null)
{
user.DepartmentId = customer.Departments.FirstOrDefault(d => d.Default)?.Id;
}
// Add user to database
var result = await userManager.CreateAsync(user);
if (!result.Succeeded)
{
context.HttpContext.Session.SetError(
"Your user does not exist in the portal. Please contact your administrator", customer.ErrorText);
return Task.FromResult(true);
}
}
else
{
//Not allowed to login if user is deactivated/resigned
if (user.ResignedDate != null)
{
context.HttpContext.Session.SetError("Your user is deactivated. Please contact your administrator", customer.ErrorText);
return Task.FromResult(true);
}
}
// Compare tenant id with user tenant
var userCustomer = await applicationDbContext.Customers.FirstOrDefaultAsync(c => c.Id == user.Department.CustomerId);
if (userCustomer == null || userCustomer.TenantId != tenantId)
{
context.HttpContext.Session.SetError("Your user does not exist in the portal. Please contact your administrator", customer.ErrorText);
return Task.FromResult(true);
}
// Sign in user
var signInManager = context.HttpContext.RequestServices.GetService<SignInManager<ApplicationUser>>();
await signInManager.SignInAsync(user, true);
}
catch (Exception ex)
{
context.HttpContext.Session.SetError("Sorry, an error occured during log in. Please contact your administrator");
}
return Task.FromResult(0);
}
// Entry point for the application.
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
最佳答案
如果存储的 Principal 对于单个 cookie 来说太大(考虑很多角色或声明),您将得到一个分块 cookie。 Cookie 的大小有限,因此分块将启动以允许主体的完全序列化。
在 ASP.NET Core 中使用 OAuth/OIDC/WS-Fed 时,是的,通常它会序列化为 cookie 身份验证 cookie,以便跨请求保存。 OAuth 可以在其结果中隐藏大量声明,因此您可以使用分块 cookie。
所以它真的是一个大 cookies ,分为多个部分,都是同一个 cookies 。因此,当涉及到您的网站按预期运行时,它们不是可选的。 (这不是 GDPR 的法律建议,需要来自实际律师)。
顺便说一句,ASP.NET Core 2.1 支持可选 cookie,您可以将 cookie 标记为必需或不需要(Cookie 身份验证将其 cookie 标记为必需),除非用户同意,否则 ASP.NET 不会写入可选 cookie供他们使用。
关于c# - 创建的 CookieAuthentication cookie 的内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50130589/
我正在为我的按钮使用 onClick 功能。我的按钮代码如下所示: Button 1 Button 2 我的 JS 函数如下所示: function fadeNext(selectedId, spee
首先,我想提一下,我理解每个人在不提供至少一些试验或错误的情况下提出问题的感受,但这纯粹是一种知识需求,话虽如此,我会去提前问。 我一直无法弄清楚如何将保存在 MySQL 表中的 600-1000 个
我想做的事情有点令人困惑,而且我英语不太好,所以我先把代码贴在这里,这样你就可以很容易地理解: 以下是表单内容: Testing for Stackoverflow Option1
我学习 SDL 二维编程已有一段时间了,现在我想创建一个结合使用 SDL 和 OpenGL 的程序。我是这样设置的: SDL_Init(SDL_INIT_VIDEO); window = SDL_Cr
我创建了 2 个 data-* 标签。数据类别和数据标签。单击 href 标签后,我想复制该数据类别和数据标签以形成输入。我的代码是:
我想用 CSS 换行。我正在使用内容。 td:before { content: "Test\A Test2"; } 它不工作。如何正确
这个问题已经有答案了: Java Class that implements Map and keeps insertion order? (8 个回答) 已关闭 6 年前。 我有一个 HashMap
我正在尝试使用 JMeter 执行端到端测试。测试涉及写入SFTP文件夹并从另一个SFTP文件夹读取写入操作生成的文件。 我能够使用 JMeter SSH SFTP 插件连接到 SFTP 文件夹,并能
您好,我有带有标准服务器端 Servlet 的 GWT 客户端。 我可以从 GWT 客户端上传文件并在服务器端读取其内容 我可以将其作为字符串发送回客户端 但是 我有 GWT FormPanel与操作
我在 Plone 4.3.9 中创建了一个自定义类型的灵巧性,称为 PersonalPage,必须只允许在特定文件夹中使用 成员文件夹/用户文件夹 . 在他的 FTI 中,默认情况下 False .
在新(更新)版本的应用程序中更改小部件布局的最佳做法是什么?当新版本提供更新、更好的小部件时,如何处理现有小部件? 最佳答案 我认为您必须向用户显示一个弹出窗口,说明“此版本中的新功能”并要求他们重新
在我的应用程序中,我使用支持 View 寻呼机和 PagerTabStrip。进入查看寻呼机我有一些 fragment ,进入其中一个我正在使用支持卡片 View 。运行应用程序后,所有卡片 View
我有以下布局文件。基本上我有谷歌地图,在左上角我有一个 TextView,我需要在其中每 15 秒保持一次计数器以刷新 map 。布局很好。
我使用如下结构: HashMap > > OverallMap 如果我这样做: OverallMap . clear ( ) clear() 丢弃的所有内容(HashMap 对象、Integer 对
我在数据库中有 1000 张图像。在页面加载时,我随机显示 60 张图片,当用户滚动时,我通过 AJAX 请求添加 20 张图片。 第一种方法 我所做的是将所有图像加载到一个容器中,然后隐藏所有图像并
我正在使用 woocommerce 创建一个网上商店。 我想在每个产品上添加一个包含产品信息的表格,例如颜色、交货时间等等。 但是当我添加这张表时。本产品消失后的所有内容。 我的表的代码: td {
This question already has an answer here: What does an empty value for the CSS property content do?
因此,我正在与我的 friend 一起为 Google Chrome 开发一个扩展程序,对于大多数功能(即日历、设置等),我们打开一个模式,这样我们就不必重定向到另一个页面。当您在内容之外单击时,我们
我将可变高度的 CSS 框设置为在更大的 div 中向左浮动。现在我想添加一个标题,其中文本在框的左侧垂直显示(旋转 90 度),如下面的链接所示(抱歉还不能发布图片)。 http://imagesh
相关页面位于 www.codykrauskopf.com/circus 如果您查看我页面的右侧,在半透明容器和浏览器窗口边缘之间有一个间隙。我看了看,出于某种原因,wrap、main、content
我是一名优秀的程序员,十分优秀!