IdentityServer4源码解析_1_项目结构

目录

简介

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();            
    builder.Services.AddOptions();
    builder.Services.AddSingleton(
        resolver => resolver.GetRequiredService>().Value);
    builder.Services.AddHttpClient();

    return builder;
}
  • 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, ConfigureInternalCookieOptions>();
    builder.Services.AddSingleton, PostConfigureInternalCookieOptions>();
    builder.Services.AddTransientDecorator();
    builder.Services.AddTransientDecorator();

    return builder;
}
  • AddCoreServices – 注入核心服务
/// 
/// Adds the core services.
/// 
/// The builder.
/// 
public static IIdentityServerBuilder AddCoreServices(this IIdentityServerBuilder builder)
{
    builder.Services.AddTransient();
    builder.Services.AddTransient();
    builder.Services.AddTransient();
    builder.Services.AddTransient();
    builder.Services.AddTransient();
    builder.Services.AddTransient();

    // todo: remove in 3.0
#pragma warning disable CS0618 // Type or member is obsolete
    builder.Services.AddTransient();
#pragma warning restore CS0618 // Type or member is obsolete

    builder.Services.AddTransient();
    builder.Services.AddTransient();

    builder.Services.AddTransient();
    builder.Services.AddScoped();
    builder.Services.AddTransient(typeof(MessageCookie<>));

    builder.Services.AddCors();
    builder.Services.AddTransientDecorator();

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

    builder.AddEndpoint(EndpointNames.Authorize, ProtocolRoutePaths.AuthorizeCallback.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.Authorize, ProtocolRoutePaths.Authorize.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.CheckSession, ProtocolRoutePaths.CheckSession.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.DeviceAuthorization, ProtocolRoutePaths.DeviceAuthorization.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.Discovery, ProtocolRoutePaths.DiscoveryWebKeys.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.Discovery, ProtocolRoutePaths.DiscoveryConfiguration.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.EndSession, ProtocolRoutePaths.EndSessionCallback.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.EndSession, ProtocolRoutePaths.EndSession.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.Introspection, ProtocolRoutePaths.Introspection.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.Revocation, ProtocolRoutePaths.Revocation.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.Token, ProtocolRoutePaths.Token.EnsureLeadingSlash());
    builder.AddEndpoint(EndpointNames.UserInfo, ProtocolRoutePaths.UserInfo.EnsureLeadingSlash());

    return builder;
}
  • AddPluggableServices – 注入可插拔服务
public static IIdentityServerBuilder AddPluggableServices(this IIdentityServerBuilder builder)
{
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient, ProtectedDataMessageStore>();
    builder.Services.TryAddTransient, ProtectedDataMessageStore>();
    builder.Services.TryAddTransient, ProtectedDataMessageStore>();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();

    builder.AddJwtRequestUriHttpClient();
    builder.AddBackChannelLogoutHttpClient();
    //builder.Services.AddHttpClient();
    //builder.Services.AddHttpClient();

    builder.Services.AddTransient();
    builder.Services.AddTransient();

    builder.Services.TryAddTransient();
    builder.Services.AddDistributedMemoryCache();

    return builder;
}
  • AddValidators – 注入校验类
public static IIdentityServerBuilder AddValidators(this IIdentityServerBuilder builder)
{
    // core
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();

    // optional
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    
    return builder;
}
  • AddResponseGenerators – 注入响应生成类
public static IIdentityServerBuilder AddResponseGenerators(this IIdentityServerBuilder builder)
{
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();
    builder.Services.TryAddTransient();

    return builder;
}
  • AddDefaultSecretParsers & AddDefaultSecretValidators
/// 
/// Adds the default secret parsers.
/// 
/// The builder.
/// 
public static IIdentityServerBuilder AddDefaultSecretParsers(this IIdentityServerBuilder builder)
{
    builder.Services.AddTransient();
    builder.Services.AddTransient();

    return builder;
}

/// 
/// Adds the default secret validators.
/// 
/// The builder.
/// 
public static IIdentityServerBuilder AddDefaultSecretValidators(this IIdentityServerBuilder builder)
{
    builder.Services.AddTransient();

    return builder;
}

IdentityServerOptions – 配置类

/// 
/// The IdentityServerOptions class is the top level container for all configuration settings of IdentityServer.
/// 
public class IdentityServerOptions
{
    /// 
    /// 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
    /// 
    /// 
    /// Unique name of this server instance, e.g. https://myissuer.com
    /// 
    public string IssuerUri { get; set; }

    /// 
    /// 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.
    /// 
    /// 
    /// Origin of this server instance, e.g. https://myorigin.com
    /// 
    public string PublicOrigin { get; set; }

    /// 
    /// Gets or sets the value for the JWT typ header for access tokens.
    /// 
    /// 
    /// The JWT typ value.
    /// 
    public string AccessTokenJwtType { get; set; } = "at+jwt";

    /// 
    /// Emits an aud claim with the format issuer/resources. That's needed for some older access token validation plumbing. Defaults to false.
    /// 
    public bool EmitLegacyResourceAudienceClaim { get; set; } = false;

    /// 
    /// Gets or sets the endpoint configuration.
    /// 
    /// 
    /// The endpoints configuration.
    /// 
    public EndpointsOptions Endpoints { get; set; } = new EndpointsOptions();

    /// 
    /// Gets or sets the discovery endpoint configuration.
    /// 
    /// 
    /// The discovery endpoint configuration.
    /// 
    public DiscoveryOptions Discovery { get; set; } = new DiscoveryOptions();

    /// 
    /// Gets or sets the authentication options.
    /// 
    /// 
    /// The authentication options.
    /// 
    public AuthenticationOptions Authentication { get; set; } = new AuthenticationOptions();

    /// 
    /// Gets or sets the events options.
    /// 
    /// 
    /// The events options.
    /// 
    public EventsOptions Events { get; set; } = new EventsOptions();

    /// 
    /// Gets or sets the max input length restrictions.
    /// 
    /// 
    /// The length restrictions.
    /// 
    public InputLengthRestrictions InputLengthRestrictions { get; set; } = new InputLengthRestrictions();

    /// 
    /// Gets or sets the options for the user interaction.
    /// 
    /// 
    /// The user interaction options.
    /// 
    public UserInteractionOptions UserInteraction { get; set; } = new UserInteractionOptions();

    /// 
    /// Gets or sets the caching options.
    /// 
    /// 
    /// The caching options.
    /// 
    public CachingOptions Caching { get; set; } = new CachingOptions();

    /// 
    /// Gets or sets the cors options.
    /// 
    /// 
    /// The cors options.
    /// 
    public CorsOptions Cors { get; set; } = new CorsOptions();

    /// 
    /// Gets or sets the Content Security Policy options.
    /// 
    public CspOptions Csp { get; set; } = new CspOptions();

    /// 
    /// Gets or sets the validation options.
    /// 
    public ValidationOptions Validation { get; set; } = new ValidationOptions();

    /// 
    /// Gets or sets the device flow options.
    /// 
    public DeviceFlowOptions DeviceFlow { get; set; } = new DeviceFlowOptions();

    /// 
    /// Gets or sets the mutual TLS options.
    /// 
    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();

    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();
    app.UseMiddleware();

    return app;
}

结语

idsv的代码量还是比较大的,注入了大量的类。但是代码风格比较规范,脉络还是很清晰的。