IdentityServer4原始碼解析_1_專案結構
阿新 • • 發佈:2020-03-27
目錄
- identityserver4原始碼解析_1_專案結構
- identityserver4原始碼解析_2_元資料介面
- identityserver4原始碼解析_3_認證介面
- identityserver4原始碼解析_4_令牌發放介面
- identityserver4原始碼解析_5_查詢使用者資訊介面
- identityserver4原始碼解析_6_結束會話介面
- identityserver4原始碼解析_7_查詢令牌資訊介面
- identityserver4原始碼解析_8_撤銷令牌介面
簡介
Security原始碼解析系列介紹了微軟提供的各種認證架構,其中OAuth2.0,OpenIdConnect屬於遠端認證架構,所謂遠端認證,是指token的頒發是由另外的站點實現的。
IdentityServer4是基於OpenIdConnect協議的認證中心框架,能夠幫助我們搭建中心化的認證服務。
可以將OpenIdConnect協議立即理解成需求文件,idsv4基於需求提供了一系列的api。
對於idsv還不太瞭解的可以看下面的資料,本系列主要學習梳理idsv的原始碼,結合協議加深理解。
曉晨姐姐系列文章
https://www.cnblogs.com/stulzq/p/8119928.html
官方文件
https://identityserver4.readthedocs.io/en/latest/
專案結構
專案地址如下
https://github.com/IdentityServer/IdentityServer4
克隆到本地,專案結構如圖
核心專案是IdentityServer4,其餘的都是與微軟框架整合、以及處理持久化的專案。
專案結構如圖。Endpoints資料夾就是介面檔案,我們先看下依賴注入、中介軟體的程式碼,然後看下每個介面。
依賴注入
public static IIdentityServerBuilder AddIdentityServer(this IServiceCollection services) { var builder = services.AddIdentityServerBuilder(); builder .AddRequiredPlatformServices() .AddCookieAuthentication() .AddCoreServices() .AddDefaultEndpoints() .AddPluggableServices() .AddValidators() .AddResponseGenerators() .AddDefaultSecretParsers() .AddDefaultSecretValidators(); // provide default in-memory implementation, not suitable for most production scenarios builder.AddInMemoryPersistedGrants(); return builder; }
- AddRequiredPlatformServices - 注入平臺服務
- IHttpContextAccessor:HttpContext訪問器
- IdentityServerOptions:配置類
public static IIdentityServerBuilder AddRequiredPlatformServices(this IIdentityServerBuilder builder) { builder.Services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); builder.Services.AddOptions(); builder.Services.AddSingleton( resolver => resolver.GetRequiredService<IOptions<IdentityServerOptions>>().Value); builder.Services.AddHttpClient(); return builder; }
- IHttpContextAccessor:HttpContext訪問器
- AddCookieAuthentication - 注入cookie服務
- 注入名稱為idsrv的cookie認證架構
- 注入IAuthenticationService的實現IdentityServerAuthenticationService
- 注入IAuthenticationHandlerProvider的實現FederatedSignoutAuthenticationHandlerProvider
public static IIdentityServerBuilder AddCookieAuthentication(this IIdentityServerBuilder builder) { builder.Services.AddAuthentication(IdentityServerConstants.DefaultCookieAuthenticationScheme) .AddCookie(IdentityServerConstants.DefaultCookieAuthenticationScheme) .AddCookie(IdentityServerConstants.ExternalCookieAuthenticationScheme); builder.Services.AddSingleton<IConfigureOptions<CookieAuthenticationOptions>, ConfigureInternalCookieOptions>(); builder.Services.AddSingleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureInternalCookieOptions>(); builder.Services.AddTransientDecorator<IAuthenticationService, IdentityServerAuthenticationService>(); builder.Services.AddTransientDecorator<IAuthenticationHandlerProvider, FederatedSignoutAuthenticationHandlerProvider>(); return builder; }
- AddCoreServices - 注入核心服務
/// <summary>
/// Adds the core services.
/// </summary>
/// <param name="builder">The builder.</param>
/// <returns></returns>
public static IIdentityServerBuilder AddCoreServices(this IIdentityServerBuilder builder)
{
builder.Services.AddTransient<SecretParser>();
builder.Services.AddTransient<SecretValidator>();
builder.Services.AddTransient<ScopeValidator>();
builder.Services.AddTransient<ExtensionGrantValidator>();
builder.Services.AddTransient<BearerTokenUsageValidator>();
builder.Services.AddTransient<JwtRequestValidator>();
// todo: remove in 3.0
#pragma warning disable CS0618 // Type or member is obsolete
builder.Services.AddTransient<BackChannelHttpClient>();
#pragma warning restore CS0618 // Type or member is obsolete
builder.Services.AddTransient<ReturnUrlParser>();
builder.Services.AddTransient<IdentityServerTools>();
builder.Services.AddTransient<IReturnUrlParser, OidcReturnUrlParser>();
builder.Services.AddScoped<IUserSession, DefaultUserSession>();
builder.Services.AddTransient(typeof(MessageCookie<>));
builder.Services.AddCors();
builder.Services.AddTransientDecorator<ICorsPolicyProvider, CorsPolicyProvider>();
return builder;
}
- AddDefaultEndpoints - 注入介面
- AuthorizeCallbackEndpoint:認證回撥介面
- AuthorizeEndpoint:認證介面
- CheckSessionEndpoint:檢查會話介面
- DeviceAuthorizationEndpoint:裝置認證介面
- DiscoveryEndpoint:元資料鍵介面
- DiscoveryEndpoint:元資料介面
- EndSessionCallbackEndpoint:結束會話回撥介面
- EndSessionEndpoint:結束會話介面
- IntrospectionEndpoint:查詢令牌資訊介面
- TokenRevocationEndpoint:撤銷令牌介面
- TokenEndpoint:發放令牌介面
- UserInfoEndpoint:查詢使用者資訊介面
public static IIdentityServerBuilder AddDefaultEndpoints(this IIdentityServerBuilder builder) { builder.Services.AddTransient<IEndpointRouter, EndpointRouter>(); builder.AddEndpoint<AuthorizeCallbackEndpoint>(EndpointNames.Authorize, ProtocolRoutePaths.AuthorizeCallback.EnsureLeadingSlash()); builder.AddEndpoint<AuthorizeEndpoint>(EndpointNames.Authorize, ProtocolRoutePaths.Authorize.EnsureLeadingSlash()); builder.AddEndpoint<CheckSessionEndpoint>(EndpointNames.CheckSession, ProtocolRoutePaths.CheckSession.EnsureLeadingSlash()); builder.AddEndpoint<DeviceAuthorizationEndpoint>(EndpointNames.DeviceAuthorization, ProtocolRoutePaths.DeviceAuthorization.EnsureLeadingSlash()); builder.AddEndpoint<DiscoveryKeyEndpoint>(EndpointNames.Discovery, ProtocolRoutePaths.DiscoveryWebKeys.EnsureLeadingSlash()); builder.AddEndpoint<DiscoveryEndpoint>(EndpointNames.Discovery, ProtocolRoutePaths.DiscoveryConfiguration.EnsureLeadingSlash()); builder.AddEndpoint<EndSessionCallbackEndpoint>(EndpointNames.EndSession, ProtocolRoutePaths.EndSessionCallback.EnsureLeadingSlash()); builder.AddEndpoint<EndSessionEndpoint>(EndpointNames.EndSession, ProtocolRoutePaths.EndSession.EnsureLeadingSlash()); builder.AddEndpoint<IntrospectionEndpoint>(EndpointNames.Introspection, ProtocolRoutePaths.Introspection.EnsureLeadingSlash()); builder.AddEndpoint<TokenRevocationEndpoint>(EndpointNames.Revocation, ProtocolRoutePaths.Revocation.EnsureLeadingSlash()); builder.AddEndpoint<TokenEndpoint>(EndpointNames.Token, ProtocolRoutePaths.Token.EnsureLeadingSlash()); builder.AddEndpoint<UserInfoEndpoint>(EndpointNames.UserInfo, ProtocolRoutePaths.UserInfo.EnsureLeadingSlash()); return builder; }
- AddPluggableServices - 注入可插拔服務
public static IIdentityServerBuilder AddPluggableServices(this IIdentityServerBuilder builder)
{
builder.Services.TryAddTransient<IPersistedGrantService, DefaultPersistedGrantService>();
builder.Services.TryAddTransient<IKeyMaterialService, DefaultKeyMaterialService>();
builder.Services.TryAddTransient<ITokenService, DefaultTokenService>();
builder.Services.TryAddTransient<ITokenCreationService, DefaultTokenCreationService>();
builder.Services.TryAddTransient<IClaimsService, DefaultClaimsService>();
builder.Services.TryAddTransient<IRefreshTokenService, DefaultRefreshTokenService>();
builder.Services.TryAddTransient<IDeviceFlowCodeService, DefaultDeviceFlowCodeService>();
builder.Services.TryAddTransient<IConsentService, DefaultConsentService>();
builder.Services.TryAddTransient<ICorsPolicyService, DefaultCorsPolicyService>();
builder.Services.TryAddTransient<IProfileService, DefaultProfileService>();
builder.Services.TryAddTransient<IConsentMessageStore, ConsentMessageStore>();
builder.Services.TryAddTransient<IMessageStore<LogoutMessage>, ProtectedDataMessageStore<LogoutMessage>>();
builder.Services.TryAddTransient<IMessageStore<EndSession>, ProtectedDataMessageStore<EndSession>>();
builder.Services.TryAddTransient<IMessageStore<ErrorMessage>, ProtectedDataMessageStore<ErrorMessage>>();
builder.Services.TryAddTransient<IIdentityServerInteractionService, DefaultIdentityServerInteractionService>();
builder.Services.TryAddTransient<IDeviceFlowInteractionService, DefaultDeviceFlowInteractionService>();
builder.Services.TryAddTransient<IAuthorizationCodeStore, DefaultAuthorizationCodeStore>();
builder.Services.TryAddTransient<IRefreshTokenStore, DefaultRefreshTokenStore>();
builder.Services.TryAddTransient<IReferenceTokenStore, DefaultReferenceTokenStore>();
builder.Services.TryAddTransient<IUserConsentStore, DefaultUserConsentStore>();
builder.Services.TryAddTransient<IHandleGenerationService, DefaultHandleGenerationService>();
builder.Services.TryAddTransient<IPersistentGrantSerializer, PersistentGrantSerializer>();
builder.Services.TryAddTransient<IEventService, DefaultEventService>();
builder.Services.TryAddTransient<IEventSink, DefaultEventSink>();
builder.Services.TryAddTransient<IUserCodeService, DefaultUserCodeService>();
builder.Services.TryAddTransient<IUserCodeGenerator, NumericUserCodeGenerator>();
builder.Services.TryAddTransient<IBackChannelLogoutService, DefaultBackChannelLogoutService>();
builder.AddJwtRequestUriHttpClient();
builder.AddBackChannelLogoutHttpClient();
//builder.Services.AddHttpClient<BackChannelLogoutHttpClient>();
//builder.Services.AddHttpClient<JwtRequestUriHttpClient>();
builder.Services.AddTransient<IClientSecretValidator, ClientSecretValidator>();
builder.Services.AddTransient<IApiSecretValidator, ApiSecretValidator>();
builder.Services.TryAddTransient<IDeviceFlowThrottlingService, DistributedDeviceFlowThrottlingService>();
builder.Services.AddDistributedMemoryCache();
return builder;
}
- AddValidators - 注入校驗類
public static IIdentityServerBuilder AddValidators(this IIdentityServerBuilder builder)
{
// core
builder.Services.TryAddTransient<IEndSessionRequestValidator, EndSessionRequestValidator>();
builder.Services.TryAddTransient<ITokenRevocationRequestValidator, TokenRevocationRequestValidator>();
builder.Services.TryAddTransient<IAuthorizeRequestValidator, AuthorizeRequestValidator>();
builder.Services.TryAddTransient<ITokenRequestValidator, TokenRequestValidator>();
builder.Services.TryAddTransient<IRedirectUriValidator, StrictRedirectUriValidator>();
builder.Services.TryAddTransient<ITokenValidator, TokenValidator>();
builder.Services.TryAddTransient<IIntrospectionRequestValidator, IntrospectionRequestValidator>();
builder.Services.TryAddTransient<IResourceOwnerPasswordValidator, NotSupportedResourceOwnerPasswordValidator>();
builder.Services.TryAddTransient<ICustomTokenRequestValidator, DefaultCustomTokenRequestValidator>();
builder.Services.TryAddTransient<IUserInfoRequestValidator, UserInfoRequestValidator>();
builder.Services.TryAddTransient<IClientConfigurationValidator, DefaultClientConfigurationValidator>();
builder.Services.TryAddTransient<IDeviceAuthorizationRequestValidator, DeviceAuthorizationRequestValidator>();
builder.Services.TryAddTransient<IDeviceCodeValidator, DeviceCodeValidator>();
// optional
builder.Services.TryAddTransient<ICustomTokenValidator, DefaultCustomTokenValidator>();
builder.Services.TryAddTransient<ICustomAuthorizeRequestValidator, DefaultCustomAuthorizeRequestValidator>();
return builder;
}
- AddResponseGenerators - 注入響應生成類
public static IIdentityServerBuilder AddResponseGenerators(this IIdentityServerBuilder builder)
{
builder.Services.TryAddTransient<ITokenResponseGenerator, TokenResponseGenerator>();
builder.Services.TryAddTransient<IUserInfoResponseGenerator, UserInfoResponseGenerator>();
builder.Services.TryAddTransient<IIntrospectionResponseGenerator, IntrospectionResponseGenerator>();
builder.Services.TryAddTransient<IAuthorizeInteractionResponseGenerator, AuthorizeInteractionResponseGenerator>();
builder.Services.TryAddTransient<IAuthorizeResponseGenerator, AuthorizeResponseGenerator>();
builder.Services.TryAddTransient<IDiscoveryResponseGenerator, DiscoveryResponseGenerator>();
builder.Services.TryAddTransient<ITokenRevocationResponseGenerator, TokenRevocationResponseGenerator>();
builder.Services.TryAddTransient<IDeviceAuthorizationResponseGenerator, DeviceAuthorizationResponseGenerator>();
return builder;
}
- AddDefaultSecretParsers & AddDefaultSecretValidators
/// <summary>
/// Adds the default secret parsers.
/// </summary>
/// <param name="builder">The builder.</param>
/// <returns></returns>
public static IIdentityServerBuilder AddDefaultSecretParsers(this IIdentityServerBuilder builder)
{
builder.Services.AddTransient<ISecretParser, BasicAuthenticationSecretParser>();
builder.Services.AddTransient<ISecretParser, PostBodySecretParser>();
return builder;
}
/// <summary>
/// Adds the default secret validators.
/// </summary>
/// <param name="builder">The builder.</param>
/// <returns></returns>
public static IIdentityServerBuilder AddDefaultSecretValidators(this IIdentityServerBuilder builder)
{
builder.Services.AddTransient<ISecretValidator, HashedSharedSecretValidator>();
return builder;
}
IdentityServerOptions - 配置類
/// <summary>
/// The IdentityServerOptions class is the top level container for all configuration settings of IdentityServer.
/// </summary>
public class IdentityServerOptions
{
/// <summary>
/// Gets or sets the unique name of this server instance, e.g. https://myissuer.com.
/// If not set, the issuer name is inferred from the request
/// </summary>
/// <value>
/// Unique name of this server instance, e.g. https://myissuer.com
/// </value>
public string IssuerUri { get; set; }
/// <summary>
/// Gets or sets the origin of this server instance, e.g. https://myorigin.com.
/// If not set, the origin name is inferred from the request
/// Note: Do not set a URL or include a path.
/// </summary>
/// <value>
/// Origin of this server instance, e.g. https://myorigin.com
/// </value>
public string PublicOrigin { get; set; }
/// <summary>
/// Gets or sets the value for the JWT typ header for access tokens.
/// </summary>
/// <value>
/// The JWT typ value.
/// </value>
public string AccessTokenJwtType { get; set; } = "at+jwt";
/// <summary>
/// Emits an aud claim with the format issuer/resources. That's needed for some older access token validation plumbing. Defaults to false.
/// </summary>
public bool EmitLegacyResourceAudienceClaim { get; set; } = false;
/// <summary>
/// Gets or sets the endpoint configuration.
/// </summary>
/// <value>
/// The endpoints configuration.
/// </value>
public EndpointsOptions Endpoints { get; set; } = new EndpointsOptions();
/// <summary>
/// Gets or sets the discovery endpoint configuration.
/// </summary>
/// <value>
/// The discovery endpoint configuration.
/// </value>
public DiscoveryOptions Discovery { get; set; } = new DiscoveryOptions();
/// <summary>
/// Gets or sets the authentication options.
/// </summary>
/// <value>
/// The authentication options.
/// </value>
public AuthenticationOptions Authentication { get; set; } = new AuthenticationOptions();
/// <summary>
/// Gets or sets the events options.
/// </summary>
/// <value>
/// The events options.
/// </value>
public EventsOptions Events { get; set; } = new EventsOptions();
/// <summary>
/// Gets or sets the max input length restrictions.
/// </summary>
/// <value>
/// The length restrictions.
/// </value>
public InputLengthRestrictions InputLengthRestrictions { get; set; } = new InputLengthRestrictions();
/// <summary>
/// Gets or sets the options for the user interaction.
/// </summary>
/// <value>
/// The user interaction options.
/// </value>
public UserInteractionOptions UserInteraction { get; set; } = new UserInteractionOptions();
/// <summary>
/// Gets or sets the caching options.
/// </summary>
/// <value>
/// The caching options.
/// </value>
public CachingOptions Caching { get; set; } = new CachingOptions();
/// <summary>
/// Gets or sets the cors options.
/// </summary>
/// <value>
/// The cors options.
/// </value>
public CorsOptions Cors { get; set; } = new CorsOptions();
/// <summary>
/// Gets or sets the Content Security Policy options.
/// </summary>
public CspOptions Csp { get; set; } = new CspOptions();
/// <summary>
/// Gets or sets the validation options.
/// </summary>
public ValidationOptions Validation { get; set; } = new ValidationOptions();
/// <summary>
/// Gets or sets the device flow options.
/// </summary>
public DeviceFlowOptions DeviceFlow { get; set; } = new DeviceFlowOptions();
/// <summary>
/// Gets or sets the mutual TLS options.
/// </summary>
public MutualTlsOptions MutualTls { get; set; } = new MutualTlsOptions();
}
UserIdentityServer - 中介軟體邏輯
- 執行校驗
- BaseUrlMiddleware中介軟體:設定BaseUrl
- 配置CORS跨域:CorsPolicyProvider根據client資訊生成動態策略
- IdentityServerMiddlewareOptions預設呼叫了UseAuthentication,所以如果使用IdentityServer不用重複註冊Authentication中介軟體
- 使用MutualTlsTokenEndpointMiddleware中介軟體:要求客戶端、服務端都使用https,預設不開啟
- 使用IdentityServerMiddleware中介軟體:IEndpointRouter根據請求尋找匹配的IEndpointHandler,如果找到的話則由EndPointHandler處理請求。
public static IApplicationBuilder UseIdentityServer(this IApplicationBuilder app, IdentityServerMiddlewareOptions options = null)
{
app.Validate();
app.UseMiddleware<BaseUrlMiddleware>();
app.ConfigureCors();
// it seems ok if we have UseAuthentication more than once in the pipeline --
// this will just re-run the various callback handlers and the default authN
// handler, which just re-assigns the user on the context. claims transformation
// will run twice, since that's not cached (whereas the authN handler result is)
// related: https://github.com/aspnet/Security/issues/1399
if (options == null) options = new IdentityServerMiddlewareOptions();
options.AuthenticationMiddleware(app);
app.UseMiddleware<MutualTlsTokenEndpointMiddleware>();
app.UseMiddleware<IdentityServerMiddleware>();
return app;
}
結語
idsv的程式碼量還是比較大的,注入了大量的類。但是程式碼風格比較規範,脈絡還是很清晰的