.net core Identity server 4登录后重定向仅在chrome中不起作用

.net core Identity server 4登录后重定向仅在chrome中不起作用,.net-core,identityserver4,.net Core,Identityserver4,我使用identity server 4,让我们称之为运行在.NETCore3.1上的“身份验证服务器”。 在重定向到身份验证服务器并提供提交登录的凭据后,存在angular应用程序请求身份验证,但不会重定向回客户端应用程序。 问题只存在于chrome浏览器中(firefox和edge可以正常工作) 我可以看到重定向请求- 但它只是返回到登录页面 客户群: public static IEnumerable<Client> GetClients() { return new

我使用identity server 4,让我们称之为运行在.NETCore3.1上的“身份验证服务器”。 在重定向到身份验证服务器并提供提交登录的凭据后,存在angular应用程序请求身份验证,但不会重定向回客户端应用程序。 问题只存在于chrome浏览器中(firefox和edge可以正常工作) 我可以看到重定向请求- 但它只是返回到登录页面 客户群:

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
                         },
        };
    }
public静态IEnumerable GetClients()
{
返回新列表(){
新客户机(){
RequireSent=false,
RequireClientSecret=false,
ClientId=“takbull clientapp dev”,
ClientName=“Takbull客户端”,
AllowedGrantTypes=GrantTypes.ImplicitAndClient Redentials,
AllowedScopes=新列表
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Profile,
“塔克布尔”,
“takbull.api”
},
//登录后重定向到哪里
重定向URI=新列表()
{
"http://localhost:4200/auth-回调/“,
"http://localhost:4200/silent-刷新.html“,
},
//TODO:添加生产URL
//注销后重定向到何处
PostLogoutRedirectUris=新列表()
{
"http://localhost:4200"
},
AllowedCorsOrigins={”http://localhost:4200"},
AllowAccessTokensViaBrowser=true,
AccessTokenLifetime=3600,
AlwaysIncludeUserClaimsInIdToken=真
},
};
}
登录代码:

[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);
}
[HttpPost]
[ValidateAntiForgeryToken]
公共异步任务登录(LoginInputModel模型,字符串按钮)
{
//检查我们是否在授权请求的上下文中
var context=await\u interaction.GetAuthorizationContextAsync(model.ReturnUrl);
//用户单击了“取消”按钮
如果(按钮!=“登录”)
{
if(上下文!=null)
{
//如果用户取消,则将结果发送回IdentityServer,就像他们
//拒绝同意(即使该客户不需要同意)。
//这将向客户端发回拒绝访问的OIDC错误响应。
wait_interaction.GrantConsentAsync(上下文、同意响应、拒绝);
//我们可以信任model.ReturnUrl,因为GetAuthorizationContextAsync返回了非null
if(wait_clientStore.IsPkceClientAsync(context.ClientId))
{
//如果客户机是PKCE,那么我们假设它是本机的,因此
//返回的响应是为最终用户提供更好的用户体验。
返回视图(“重定向”,新的重定向视图模型{RedirectUrl=model.ReturnUrl});
}
返回重定向(model.ReturnUrl);
}
其他的
{
//因为我们没有有效的上下文,所以我们只需返回主页
返回重定向(“~/”);
}
}
if(ModelState.IsValid)
{
//根据内存存储验证用户名/密码
var ValidResp=await_users.ValidateCredentials(model.Username,model.Password);
if(ValidResp.LogInStatus==LogInStatus.Success)
{
var user=\u users.FindByUsername(model.Username);
//wait_events.RaiseAsync(新用户登录访问事件(user.Username,user.SubjectId,user.Username));
wait_events.RaiseAsync(新的userloginsAccessEvent(user.Email,user.UserId.ToString(),user.Email));
//仅当用户选择“记住我”时才在此处设置显式过期。
//否则,我们依赖于cookie中间件中配置的过期。
AuthenticationProperties props=null;
if(AccountOptions.AllowRememberLogin&&model.RememberLogin)
{
props=新的AuthenticationProperties
{
ispersist=true,
ExpiresUtc=DateTimeOffset.Now.Add(AccountOptions.RememberLoginDuration)
};
};
//发出具有主题ID和用户名的身份验证cookie
//等待HttpContext.SignInAsync(user.SubjectId、user.Username、props);
//发出具有主题ID和用户名的身份验证cookie
等待HttpContext.SignInAsync(user.UserId.ToString(),user.FirstName+“”+user.LastName,props,_users.GetClaims(user.ToArray());
if(上下文!=null)
{
if(wait_clientStore.IsPkceClientAsync(context.ClientId))
{
//如果客户机是PKCE,那么我们假设它是本机的,因此
//返回的响应是为最终用户提供更好的用户体验。
返回视图(“重定向”,新的重定向视图模型{RedirectUrl=model.ReturnUrl});
}
//我们可以信任model.ReturnUrl,因为GetAuthorizationContextAsync返回了非null
返回重定向(model.ReturnUrl);
}
//请求本地页面
if(Url.IsLocalUrl(model.ReturnUrl))
{
返回重定向(model.ReturnUrl);
}
else if(string.IsNullOrEmpty(m
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
});
 if (userAgent.Contains("Chrome/8"))
 {
     return true;
 }
CorrelationCookie.SameSite = SameSiteMode.Lax;
NonceCookie.SameSite = SameSiteMode.Lax;
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ...)
    {
            app.UseCookiePolicy(new CookiePolicyOptions
            {
                MinimumSameSitePolicy = SameSiteMode.Lax
            });
services.AddAuthentication("MyCookie")
                .AddCookie("MyCookie", options =>
                {
                    options.ExpireTimeSpan = new TimeSpan(24, 0, 0);
                });