猿问

仍已登录 MVC 站点,但无法调用 Web API

我有一个 ASP.NET MVC站点,IdentityServer4主机和一个Web API。


当我使用外部提供商(Facebook)登录MVC站点时,我登录正常。从MVC站点,我还可以正确使用Web API。


但是,第二天,我仍然登录到MVC站点,但是当我尝试访问Web API时,我得到一个“未经授权的例外”。


因此,尽管我仍然登录到 MVC 站点,但我不再通过身份验证从 MVC 站点中调用 Web API。


我想知道如何处理这种情况,以及如何配置IdentityServer4。


为什么一天后我仍然登录到 MVC 站点?如何配置?

如果我仍然登录到 MVC 站点,为什么我仍然无法调用 Web API?

我可以同步过期时间吗?或者我应该如何处理这个问题?

MVC 应用程序的配置如下:


 services.AddAuthentication(options =>

        {

            options.DefaultScheme = "Cookies";

            options.DefaultChallengeScheme = "oidc"; 

        })

        .AddCookie("Cookies")

        .AddOpenIdConnect("oidc", options =>

        {

            options.SignInScheme = "Cookies";

            options.Authority = mgpIdSvrSettings.Authority;

            options.RequireHttpsMetadata = false;                

            options.ClientId = mgpIdSvrSettings.ClientId;

            options.ClientSecret = mgpIdSvrSettings.ClientSecret; // Should match the secret at IdentityServer

            options.ResponseType = "code id_token"; // Use hybrid flow

            options.SaveTokens = true;                

            options.GetClaimsFromUserInfoEndpoint = true;                

            options.Scope.Add("mgpApi");

            options.Scope.Add("offline_access");                  

        });            

所以它使用混合流。


在 IdentityServer 中,MVC 客户端的配置如下:


new Client

{

     EnableLocalLogin = false,


     ClientId = "mgpPortal",

     ClientName = "MGP Portal Site",

     AllowedGrantTypes = GrantTypes.Hybrid,


     // where to redirect to after login

     RedirectUris = mgpPortalSite.RedirectUris,


     // where to redirect to after logout

     PostLogoutRedirectUris = mgpPortalSite.PostLogoutRedirectUris,


     // secret for authentication

     ClientSecrets = mgpPortalSite.ClientSecrets.Select(cs => new Secret(cs.Sha256())).ToList(),

狐的传说
浏览 67回答 1
1回答

倚天杖

有两种类型的身份验证,cookie 和持有者。如果 Cookie 使您保持登录状态,则持有者令牌无法登录。因为持有者令牌设置为在某个时刻过期,不允许更改生存期。访问令牌过期后访问资源 (api) 的唯一方法是让用户再次登录或使用刷新令牌请求新的访问令牌,而无需用户交互。您已经配置了它:options.Scope.Add("offline_access");每次登录时,请求将至少包含一个刷新令牌。将其存放在安全的地方,并在需要时使用。默认情况下,它设置为仅一次使用。您可以使用类似此代码的内容来续订令牌(因为您实际上不是在刷新它,而是在替换它)。需要包含“标识模型”NuGet 包,如标识服务器的示例所示。private async Task<TokenResponse> RenewTokensAsync(){&nbsp; &nbsp; // Initialize the token endpoint:&nbsp; &nbsp; var client = _httpClientFactory.CreateClient();&nbsp; &nbsp; var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");&nbsp; &nbsp; if (disco.IsError) throw new Exception(disco.Error);&nbsp; &nbsp; // Read the stored refresh token:&nbsp; &nbsp; var rt = await HttpContext.GetTokenAsync("refresh_token");&nbsp; &nbsp; var tokenClient = _httpClientFactory.CreateClient();&nbsp; &nbsp; // Request a new access token:&nbsp; &nbsp; var tokenResult = await tokenClient.RequestRefreshTokenAsync(new RefreshTokenRequest&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; Address = disco.TokenEndpoint,&nbsp; &nbsp; &nbsp; &nbsp; ClientId = "mvc",&nbsp; &nbsp; &nbsp; &nbsp; ClientSecret = "secret",&nbsp; &nbsp; &nbsp; &nbsp; RefreshToken = rt&nbsp; &nbsp; });&nbsp; &nbsp; if (!tokenResult.IsError)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var old_id_token = await HttpContext.GetTokenAsync("id_token");&nbsp; &nbsp; &nbsp; &nbsp; var new_access_token = tokenResult.AccessToken;&nbsp; &nbsp; &nbsp; &nbsp; var new_refresh_token = tokenResult.RefreshToken;&nbsp; &nbsp; &nbsp; &nbsp; var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn);&nbsp; &nbsp; &nbsp; &nbsp; // Save the information in the cookie&nbsp; &nbsp; &nbsp; &nbsp; var info = await HttpContext.AuthenticateAsync("Cookies");&nbsp; &nbsp; &nbsp; &nbsp; info.Properties.UpdateTokenValue("refresh_token", new_refresh_token);&nbsp; &nbsp; &nbsp; &nbsp; info.Properties.UpdateTokenValue("access_token", new_access_token);&nbsp; &nbsp; &nbsp; &nbsp; info.Properties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));&nbsp; &nbsp; &nbsp; &nbsp; await HttpContext.SignInAsync("Cookies", info.Principal, info.Properties);&nbsp; &nbsp; &nbsp; &nbsp; return tokenResult;&nbsp; &nbsp; }&nbsp; &nbsp; return null;}默认情况下,刷新令牌用法配置为一次性使用。请注意,当存储新的刷新令牌失败并且你应该丢失它时,请求新的刷新令牌的唯一方法是强制用户再次登录。另请注意,刷新令牌可能会过期。退后一步,当访问令牌过期或即将过期时,需要使用它:var accessToken = await HttpContext.GetTokenAsync("access_token");var tokenHandler = new JwtSecurityTokenHandler();var jwtSecurityToken = tokenHandler.ReadJwtToken(accessToken);// Depending on the lifetime of the access token.// This is just an example. An access token may be valid// for less than one minute.if (jwtSecurityToken.ValidTo < DateTime.UtcNow.AddMinutes(5)){&nbsp; &nbsp; var responseToken = await RenewTokensAsync();&nbsp; &nbsp; if (responseToken == null)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; throw new Exception("Error");&nbsp; &nbsp; }&nbsp; &nbsp; accessToken = responseToken.AccessToken;}// Proceed, accessToken contains a valid token.
随时随地看视频慕课网APP
我要回答