IdentityServer4 学习笔记-令牌和跨域设置

563 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

1. 设置令牌

由于访问令牌的生命周期有限,因此刷新令牌允许在没有用户交互的情况下请求新的访问令牌,以下流程支持刷新令牌:授权代码,混合和资源所有者密码凭据流。需要明确授权客户端通过设置AllowOfflineAccess来请求刷新令牌true

  1. AbsoluteRefreshTokenLifetime
    刷新令牌的最长生命周期(秒)。默认为2592000秒/ 30天。零允许刷新令牌,当仅在SlidingRefreshTokenLifetime传递后使用时过期。RefreshTokenExpiration = Sliding

  2. SlidingRefreshTokenLifetime
    以秒为单位滑动刷新令牌的生命周期。默认为1296000秒/ 15天

  3. RefreshTokenUsage
    ReUse 刷新令牌时,刷新令牌句柄将保持不变 OneTime 刷新令牌时将更新刷新令牌句柄

  4. RefreshTokenExpiration
    Absolute 刷新令牌将在固定时间点到期(由AbsoluteRefreshTokenLifetime指定) Sliding刷新令牌时,将刷新刷新令牌的生命周期(按SlidingRefreshTokenLifetime中指定的数量)。生命周期不会超过 AbsoluteRefreshTokenLifetime

  5. UpdateAccessTokenClaimsOnRefresh
    获取或设置一个值,该值指示是否应在刷新令牌请求上更新访问令牌。

2.引用令牌

访问令牌有两种形式 包含或引用,JWT令牌将是一个包含的访问令牌 - 它是一个带有声明和过期的受保护数据结构。一旦API了解了密钥材料,它就可以验证自包含的令牌,而无需与发行者进行通信。这使得JWT难以撤销。它们将一直有效,直到它们过期。

使用引用令牌时 - IdentityServer会将令牌的内容存储在数据存储中,并且只会将此令牌的唯一标识符发回给客户端。然后,接收此引用的API必须打开与IdentityServer的反向通道通信以验证令牌。

可以使用以下设置切换客户端的令牌类型:

client.AccessTokenType = AccessTokenType.Reference;

IdentityServer提供了OAuth 2.0内省规范的实现,该规范允许API取消引用令牌。您可以使用我们的专用内省处理程序或使用身份服务器身份验证处理程序,它可以验证JWT和引用令牌。

内省端点需要身份验证 - 因为内省端点的客户端是API,您可以在以下位置配置秘密ApiResource

var api = new ApiResource("api1")
{
    ApiSecrets = { new Secret("secret".Sha256()) }
}
3. 自定义令牌请求验证

可以在令牌端点处将自定义代码作为令牌颁发管道的一部分运行

  1. 添加额外的验证逻辑

  2. 动态地改变某些参数(例如令牌生存期)

实现(并注册)ICustomTokenRequestValidator接口:

public interface ICustomTokenRequestValidator
{
    Task ValidateAsync(CustomTokenRequestValidationContext context);
}

上下文对象使您可以访问:

  1. 添加自定义响应参数

  2. 返回错误和错误说明

  3. 修改请求参数,例如访问令牌生存期和类型,客户端声明和确认方法

您可以使用配置构建器上的AddCustomTokenRequestValidator扩展方法注册验证程序的实现。

二、跨域配置
1.基于客户端的CORS配置

IdentityServer中的许多端点将通过基于JavaScript的客户端的Ajax调用进行访问。鉴于IdentityServer最有可能托管在与这些客户端不同的源上,这意味着需要配置跨源资源共享(CORS)。

配置CORS的一种方法是在客户端配置上使用AllowedCorsOrigins该集合。只需将客户端的原点添加到集合中,IdentityServer中的默认配置将查询这些值以允许来自源的跨源调用。

配置CORS时,请务必使用原点(不是URL)。例如:https://foo:123/是一个URL,而是https://foo:123一个原点。

如果您使用我们提供的“内存中”或基于EF的客户端配置,则将使用此默认CORS实现。如果您定义自己的IClientStore,那么您将需要实现自己的自定义CORS策略服务。

2. 自定义Cors策略服务

IdentityServer允许托管应用程序实现ICorsPolicyService完全控制CORS策略。

要实现单一的方法是:Task<bool> IsOriginAllowedAsync(string origin)。如果允许原点则返回true,否则返回false

实现后,只需在DI中注册实现,然后IdentityServer将使用您的自定义实现。

如果您只是希望对一组允许的原点进行硬编码,那么您可以使用一个预先构建ICorsPolicyService的实现调用DefaultCorsPolicyService。这将被配置为DI单例,并以其硬编码的AllowedOrigins收集,或设置标志AllowAll为true允许所有的源点。例如,在ConfigureServices

var cors = new DefaultCorsPolicyService(_loggerFactory.CreateLogger<DefaultCorsPolicyService>())
{
    AllowedOrigins = { "https://foo", "https://bar" }
};
services.AddSingleton<ICorsPolicyService>(cors);
3.IdentityServer与ASP.NET Core的CORS策略混合

IdentityServer使用ASP.NET Core的CORS中间件来提供其CORS实现。托管IdentityServer的应用程序可能还需要CORS用于自己的自定义端点。通常,两者应该在同一个应用程序中一起工作。

您的代码应使用ASP.NET Core中记录的CORS功能,而不考虑IdentityServer。这意味着您应该定义策略并正常注册中间件。如果您的应用程序在ConfigureServices中定义了策略,那么这些策略应继续在您使用它们的相同位置(在您配置CORS中间件的地方或在EnableCors控制器代码中使用MVC 属性的位置)。相反,如果您使用CORS中间件(通过策略构建器回调)定义内联策略,那么它也应该继续正常工作。

您使用ASP.NET Core CORS服务与IdentityServer之间可能存在冲突的一种情况是您决定创建自定义ICorsPolicyProvider。鉴于ASP.NET Core的CORS服务和中间件的设计,IdentityServer实现了自己的自定义ICorsPolicyProvider并将其注册到DI系统中。幸运的是,IdentityServer实现旨在使用装饰器模式来包装ICorsPolicyProvider已在DI中注册的任何现有模式 。这意味着你也可以实现ICorsPolicyProvider,但它只需要在DI中的IdentityServer之前注册(例如,在ConfigureServices)。

一、.添加新协议

除了对OpenID Connect和OAuth 2.0的内置支持之外,IdentityServer4还允许添加对其他协议的支持。

您可以将这些附加协议端点添加为中间件或使用例如MVC控制器。在这两种情况下,您都可以访问ASP.NET Core DI系统,该系统允许重用我们的内部服务,例如访问客户端定义或密钥材料。

可以在此处找到添加WS-Federation支持的示例。

1 典型认证工作流程

身份验证请求通常如下所示:

  • 身份验证请求到达协议端点
  • 协议端点执行输入验证
  • 重定向到登录页面,返回URL设置回协议端点(如果用户是匿名的)
    • 通过访问当前请求详细信息 IIdentityServerInteractionService
    • 用户身份验证(本地或通过外部身份验证中间件)
    • 登录用户
    • 重定向回协议端点
  • 创建协议响应(令牌创建和重定向回客户端)
2 .访问配置并重定向到登录页面

要实现上述工作流程,需要与IdentityServer建立一些交互点。

您可以通过将IdentityServerOptions类注入代码来访问IdentityServer配置。这个,例如具有登录页面的配置路径:

var returnUrl = Url.Action("Index");
returnUrl = returnUrl.AddQueryString(Request.QueryString.Value);

var loginUrl = _options.UserInteraction.LoginUrl;
var url = loginUrl.AddQueryString(_options.UserInteraction.LoginReturnUrlParameter, returnUrl);

return Redirect(url);
3. 登录页面与当前协议请求之间的交互

所述IIdentityServerInteractionService支撑件转动一个协议返回URL成解析和验证上下文对象:

var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

默认情况下,交互服务仅了解OpenID Connect协议消息。要扩展支持,您可以自己编写IReturnUrlParser

public interface IReturnUrlParser
{
    bool IsValidReturnUrl(string returnUrl);
    Task<AuthorizationRequest> ParseAsync(string returnUrl);
}

..然后在DI中注册解析器:

builder.Services.AddTransient<IReturnUrlParser, WsFederationReturnUrlParser>();

这允许登录页面获取客户端配置和其他协议参数等信息。

4.访问用于创建协议响应的配置

通过将IKeyMaterialService代码注入到代码中,您可以访问配置的签名凭据和验证密钥:

var credential = await _keys.GetSigningCredentialsAsync();
var key = credential.Key as Microsoft.IdentityModel.Tokens.X509SecurityKey;

var descriptor = new SecurityTokenDescriptor
{
    AppliesToAddress = result.Client.ClientId,
    Lifetime = new Lifetime(DateTime.UtcNow, DateTime.UtcNow.AddSeconds(result.Client.IdentityTokenLifetime)),
    ReplyToAddress = result.Client.RedirectUris.First(),
    SigningCredentials = new X509SigningCredentials(key.Certificate, result.RelyingParty.SignatureAlgorithm, result.RelyingParty.DigestAlgorithm),
    Subject = outgoingSubject,
    TokenIssuerName = _contextAccessor.HttpContext.GetIdentityServerIssuerUri(),
    TokenType = result.RelyingParty.TokenType
};