为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
狐的传说 2022-08-20 17:21:29
我有一个 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(),
查看完整描述

1 回答

?
倚天杖

TA贡献1828条经验 获得超3个赞

有两种类型的身份验证,cookie 和持有者。


如果 Cookie 使您保持登录状态,则持有者令牌无法登录。因为持有者令牌设置为在某个时刻过期,不允许更改生存期。


访问令牌过期后访问资源 (api) 的唯一方法是让用户再次登录或使用刷新令牌请求新的访问令牌,而无需用户交互。


您已经配置了它:


options.Scope.Add("offline_access");

每次登录时,请求将至少包含一个刷新令牌。将其存放在安全的地方,并在需要时使用。默认情况下,它设置为仅一次使用。


您可以使用类似此代码的内容来续订令牌(因为您实际上不是在刷新它,而是在替换它)。需要包含“标识模型”NuGet 包,如标识服务器的示例所示。


private async Task<TokenResponse> RenewTokensAsync()

{

    // Initialize the token endpoint:

    var client = _httpClientFactory.CreateClient();

    var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");


    if (disco.IsError) throw new Exception(disco.Error);


    // Read the stored refresh token:

    var rt = await HttpContext.GetTokenAsync("refresh_token");

    var tokenClient = _httpClientFactory.CreateClient();


    // Request a new access token:

    var tokenResult = await tokenClient.RequestRefreshTokenAsync(new RefreshTokenRequest

    {

        Address = disco.TokenEndpoint,


        ClientId = "mvc",

        ClientSecret = "secret",

        RefreshToken = rt

    });


    if (!tokenResult.IsError)

    {

        var old_id_token = await HttpContext.GetTokenAsync("id_token");

        var new_access_token = tokenResult.AccessToken;

        var new_refresh_token = tokenResult.RefreshToken;

        var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn);


        // Save the information in the cookie

        var info = await HttpContext.AuthenticateAsync("Cookies");


        info.Properties.UpdateTokenValue("refresh_token", new_refresh_token);

        info.Properties.UpdateTokenValue("access_token", new_access_token);

        info.Properties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));


        await HttpContext.SignInAsync("Cookies", info.Principal, info.Properties);

        return tokenResult;

    }

    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))

{

    var responseToken = await RenewTokensAsync();

    if (responseToken == null)

    {

        throw new Exception("Error");

    }

    accessToken = responseToken.AccessToken;

}


// Proceed, accessToken contains a valid token.


查看完整回答
反对 回复 2022-08-20
  • 1 回答
  • 0 关注
  • 66 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号