仍登录MVC网站,但无法调用Web API - c#

我有一个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(),

     AllowedScopes = new List<string>
     {
            IdentityServerConstants.StandardScopes.OpenId,
            IdentityServerConstants.StandardScopes.Profile,
            "mgpApi"
     },

     AllowOfflineAccess = true,                             
     RequireConsent = false,
},

最后是Web API:

 services.AddAuthentication("Bearer")                
           .AddIdentityServerAuthentication(options =>
            {
                options.Authority = mgpIdSvrSettings.Authority;
                options.RequireHttpsMetadata = false;                    
                options.ApiName = mgpIdSvrSettings.ApiName;
                options.EnableCaching = true;
                options.CacheDuration = TimeSpan.FromMinutes(10);                    
            });

参考方案

身份验证有两种类型,即Cookie和承载。

Cookie使您保持登录状态,而承载令牌则不能。因为不记名令牌被设置为在某个时间点到期,而不允许您更改生存期。

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

您已经配置了它:

options.Scope.Add("offline_access");

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

您可以使用类似此代码的方式来更新令牌(因为您实际上并未刷新令牌,而是对其进行了替换)。您需要包括'IdentityModel'NuGet软件包,如IdentityServer的示例所示。

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;
}

默认情况下,刷新令牌的使用是configured一次。请注意,当存储新的刷新令牌失败时,您应该丢失它,那么请求新的刷新令牌的唯一方法是强制用户再次登录。

另请注意,刷新令牌可能会过期。

再退一步,当访问令牌过期或即将过期时,您将需要使用它:

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.

改造正在返回一个空的响应主体 - java

我正在尝试使用Retrofit和Gson解析一些JSON。但是,我得到的响应机构是空的。当我尝试从对象中打印信息时,出现NullPointerException。我确保URL正确,并且我也确保POJO也正确。我正在使用jsonschema2pojo来帮助创建POJO类。这是我要解析的JSON{ "?xml": { "@versi…

ASP.NET Web API 2中AuthorizeAttribute发生了什么变化? - c#

我已经将项目和一组单元测试从ASP.NET Web API升级到ASP.NET Web API 2。我们将自定义DelegatingHandler用于自定义身份验证机制。它将Thread.CurrentPrincipal和HttpContext.Current.User设置为适当的System.Security.Claims.ClaimsPrincipal。…

从代码和网站调用Web API - c#

首先,我使用C#4.0作为编码语言。我相信我看到了一些答案,其中4.5引入了一些可以使此操作变得容易得多的方法,但这不是我要求更改框架。我正在创建一个MVC4 WebApi,它将同时被网站和C#代码使用(在另一个项目中)。通常,当从JavaScript调用时,我会这样做:$.ajax({ dataType: 'text', url: &#…

我需要帮助将此REST API Curl命令转换为Python请求 - python

我在这里是新手,老实说对所有编码都是新手。我正在尝试创建一个Pyton脚本,以使用REST API从Request Tracker资产数据库中搜索项目。到目前为止,我得到了以下Curl命令:curl -X POST \ -H "Content-Type: application/json" \ -d '[{ "fiel…

从Javascript将文件对象传递到Web API - javascript

我正在尝试通过Javscript Web API调用中的Web API将文件从本地计算机上传到共享点。试图将文件对象从javascript传递到Web api,但我一直在获取诸如类型错误,找不到资源等错误,任何人都可以帮忙。JavaScript代码: $scope.Upload = function () { if (!window.FileReader) …