public static IEnumerable<Client> GetClients()
{
return new List<Client>(){
new Client() {
RequireConsent =false,
RequireClientSecret = false,
ClientId = "takbull-clientapp-dev",
ClientName = "Takbull Client",
AllowedGrantTypes = GrantTypes.ImplicitAndClientCredentials,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Profile,
"takbull",
"takbull.api"
},
// where to redirect to after login
RedirectUris = new List<string>()
{
"http://localhost:4200/auth-callback/",
"http://localhost:4200/silent-refresh.html",
},
//TODO: Add Production URL
// where to redirect to after logout
PostLogoutRedirectUris =new List<string>()
{
"http://localhost:4200"
},
AllowedCorsOrigins = {"http://localhost:4200"},
AllowAccessTokensViaBrowser = true,
AccessTokenLifetime = 3600,
AlwaysIncludeUserClaimsInIdToken = true
},
};
}
登录代码:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginInputModel model, string button)
{
// check if we are in the context of an authorization request
var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
// the user clicked the "cancel" button
if (button != "login")
{
if (context != null)
{
// if the user cancels, send a result back into IdentityServer as if they
// denied the consent (even if this client does not require consent).
// this will send back an access denied OIDC error response to the client.
await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
if (await _clientStore.IsPkceClientAsync(context.ClientId))
{
// if the client is PKCE then we assume it's native, so this change in how to
// return the response is for better UX for the end user.
return View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
}
return Redirect(model.ReturnUrl);
}
else
{
// since we don't have a valid context, then we just go back to the home page
return Redirect("~/");
}
}
if (ModelState.IsValid)
{
// validate username/password against in-memory store
var ValidResp = await _users.ValidateCredentials(model.Username, model.Password);
if (ValidResp.LogInStatus == LogInStatus.Success)
{
var user = _users.FindByUsername(model.Username);
//await _events.RaiseAsync(new UserLoginSuccessEvent(user.Username, user.SubjectId, user.Username));
await _events.RaiseAsync(new UserLoginSuccessEvent(user.Email, user.UserId.ToString(), user.Email));
// only set explicit expiration here if user chooses "remember me".
// otherwise we rely upon expiration configured in cookie middleware.
AuthenticationProperties props = null;
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.Now.Add(AccountOptions.RememberMeLoginDuration)
};
};
// issue authentication cookie with subject ID and username
//await HttpContext.SignInAsync(user.SubjectId, user.Username, props);
// issue authentication cookie with subject ID and username
await HttpContext.SignInAsync(user.UserId.ToString(), user.FirstName + " " + user.LastName, props, _users.GetClaims(user).ToArray());
if (context != null)
{
if (await _clientStore.IsPkceClientAsync(context.ClientId))
{
// if the client is PKCE then we assume it's native, so this change in how to
// return the response is for better UX for the end user.
return View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
}
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
return Redirect(model.ReturnUrl);
}
// request for a local page
if (Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
else if (string.IsNullOrEmpty(model.ReturnUrl))
{
return Redirect("~/");
}
else
{
// user might have clicked on a malicious link - should be logged
throw new Exception("invalid return URL");
}
}
await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, ValidResp.ResponseDescription));
ModelState.AddModelError(string.Empty, ValidResp.ResponseDescription);
}
// something went wrong, show form with error
var vm = await BuildLoginViewModelAsync(model);
return View(vm);
}
答案 0 :(得分:8)
.NET Core 2.2上的IdentityServer4也有类似的问题。您的问题可能与新的浏览器版本(例如Chrome或Firefox)中的重大更改有关:
对我来说,可行的解决方案是完全关闭cookie的 SameSite 配置。此处介绍了.NET Core 2.2的这种可能性:
https://docs.microsoft.com/en-us/aspnet/core/security/samesite?view=aspnetcore-3.1
((如果您的解决方案在.NET Core 3.1上,则在下面的代码中,而不是使用(SameSiteMode)(-1),而应使用 SameSiteMode.Unspecified )>
FIX: 在 IdentityServerBuilder 创建后的 ConfigureServices 方法中的 Startup.cs 文件中...
var builder = services.AddIdentityServer(options =>
{....});
...我添加了以下配置更改:
builder.Services.ConfigureExternalCookie(options => {
options.Cookie.IsEssential = true;
options.Cookie.SameSite = (SameSiteMode)(-1); //SameSiteMode.Unspecified in .NET Core 3.1
});
builder.Services.ConfigureApplicationCookie(options => {
options.Cookie.IsEssential = true;
options.Cookie.SameSite = (SameSiteMode)(-1); //SameSiteMode.Unspecified in .NET Core 3.1
});
答案 1 :(得分:5)
我最近在chrome和edge上遇到问题,但几个月前还只有chrome。 因此,对于我来说,.Net Core 3和IdentityServer4版本3.1.2通过将以下代码添加到startup.cs开始工作:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ...)
{
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.Lax
});
注意:请确保将此策略添加到Configure方法的开头,而不是在启动时结束。否则cs无效。
答案 2 :(得分:4)
您将在Google Chrome中进入控制台警告,并且您的身份服务器无法重定向到适用于Chrome 80版的客户端应用。
与资源at相关联的cookie设置为SameSite = None,但未设置安全。它已被阻止,因为Chrome现在仅发送标记为SameSite = None的cookie(如果它们也被标记为Secure)。您可以在Application> Storage> Cookies下的开发人员工具中查看cookie,并在https://www.chromestatus.com/feature/5633521622188032上查看更多详细信息。
要解决此问题,您需要进行以下链接中提及的更改-
https://www.thinktecture.com/en/identity/samesite/prepare-your-identityserver/
注意:对于.Net Core 2.2,设置SameSite =(SameSiteMode)(-1),对于.Net Core 3.0或更高版本,设置SameSite = SameSiteMode.Unspecified
此外,对于Chrome 80版本,请添加此额外条件-
if (userAgent.Contains("Chrome/8"))
{
return true;
}
答案 3 :(得分:2)
设置OpenidConnectionOptions对我有用
CorrelationCookie.SameSite = SameSiteMode.Lax;
NonceCookie.SameSite = SameSiteMode.Lax;
答案 4 :(得分:0)
您应该在 Startup.cs 的 ConfigureServices 范围内添加以下代码
services.AddAuthentication("MyCookie")
.AddCookie("MyCookie", options =>
{
options.ExpireTimeSpan = new TimeSpan(24, 0, 0);
});