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