短版本:是确定..net Core-2中CookieAuthentication机制创建的cookie内容的方法吗?
上下文:
我目前正致力于使一个网站GDPR兼容,这意味着记录所有使用和设置在我们的网站上的cookie。我们使用asp.net核心2和标识来处理用户登录和注销。问题是所有由身份设置的cookie以及如何记录它们。曲奇1.
这个曲奇是直接向前,它包含登录信息,特权等。如果你删除它,你将从我们的网站注销。它对我们的应用程序至关重要,因此无需担心。
问题是下面的cookie (注)。这是一个曲奇分成三个部分)
它是使用和设置的cookieAuthentication,但实际上似乎不做任何事情。您可以从浏览器中删除它们,并且仍然可以使用该站点。例如,进行更改并保存我,就不会强行退出。
这带来了一个问题,因为根据新的GDPR法律,如果这些cookie块是可选的,用户应该能够禁用它们。(以后有问题)
然后,的问题变成了:,如何才能找到这个cookie的功能和它包含的信息。这两者都同样重要。
尝试了一些方法:--我试着在源代码中寻找答案,但是项目开发已经断断续续地进行了两年,而且完全是杂乱无章的工作。我还试图用这个帖子How to manually decrypt an ASP.NET Core Authentication cookie?作为指导来解密cookie,但是我在C#中开发的时间还不到4个月,所以我无法让它工作,因为它似乎针对的是一个更老的/不同版本的..net core。
Note!,因为这是我在堆栈上的第一个问题,我欢迎关于如何使我的问题更清晰或更有用于这个站点的一般大众的建议和技巧。
Edit_1:,好吧,实际上在startupfile中没有太多的配置
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true
});有一些代码可以用微软启用OpenId。但会被放进这个饼干里吗?
// 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();
}
}发布于 2018-05-02 12:54:34
如果存储的主体对于单个cookie来说太大,就会得到块cookie (请考虑很多角色或声明)。Cookie的大小有限,因此分块将启动以允许主体完全序列化。
当涉及到在ASP.NET核心中使用OAuth/OIDC/WS-Fed时,是的,通常会将其序列化为cookie身份验证cookie,以便在请求之间保存。OAuth可以在其结果中屏蔽大量的声明,因此您可以使用块饼干。
所以它真的是一个大饼干,在多个部分,都是相同的曲奇。因此,当涉及到您的站点运行时,它们不是可选的。(这不是GDPR的法律建议,这需要一名真正的律师提供)。
由于ASP.NET Core2.1附带了对可选cookie的支持,您可以根据需要标记一个Cookie (Cookie身份验证将其Cookie标记为需要),除非用户同意使用Cookie,否则ASP.NET不会编写可选Cookie。
https://stackoverflow.com/questions/50130589
复制相似问题