• 基于 IdentityServer3 实现 OAuth 2.0 授权服务数据持久化


    最近花了一点时间,阅读了IdentityServer的源码,大致了解项目整体的抽象思维、面向对象的重要性; 生产环境如果要使用 IdentityServer3 ,主要涉及授权服务,资源服务的部署负载的问题,客户端(clients),作用域(scopes),票据(token)一定都要持久化, 客户端与作用域的持久化只需要实现 IClientStore 与 IScopeStore 的接口,可以自己实现,也可以直接使用 IdentityServer3 自身的扩展 IdentityServer3.EntityFramework

    Package

    核心类库
    Install-Package IdentityServer3
    IdentityServer 核心库,只支持基于内存的客户端信息与用户信息配置

    配置信息持久化
    客户端,作用域,票据的持久化 ,支持的扩展有两个,一个基于 EF,另外一个使用MongoDb(社区支持)
    Install-Package IdentityServer3.EntityFramework
    Install-Package IdentityServer.v3.MongoDb

    用户持久化

    用户的持久化支持 MembershipReboot 与 ASP.NET Identity 两种
    Install-Package IdentityServer3.MembershipReboot
    Install-Package IdentityServer3.AspNetIdentity

    其他插件

    WS-Federation
    Install-Package IdentityServer3.WsFederation
    Access token validation middleware(验证中间件)
    Install-Package IdentityServer3.AccessTokenValidation

    国际化

    https://github.com/johnkors/IdentityServer3.Contrib.Localization

    缓存

    https://github.com/AliBazzi/IdentityServer3.Contrib.RedisStore

    客户端

    https://github.com/IdentityModel/IdentityModel2

    配置信息持久化(Entity Framework support for Clients, Scopes, and Operational Data)

    客户端(clients)与作用域(scopes)的持久化

    客户端与作用域的持久化只需要实现 IClientStore 与 IScopeStore 的接口,默认EF 在 IdentityServerServiceFactory 实现了 RegisterClientStore 与 RegisterScopeStore 两个扩展方法,也可以使用 RegisterConfigurationServices 方法,默认包含以上两个扩展方法合集;RegisterOperationalServices 扩展方法实现 IAuthorizationCodeStore, ITokenHandleStore, IRefreshTokenStore, and IConsentStore 功能等。

    可以在 IdentityServer3.EntityFramework 的项目中找到数据库的初始SQL

    ER 关系OAuth项目结构

    image

    IdentityServerServiceFactoryExtensions 类扩展 IdentityServerServiceFactory 实现方法来持久化信息,最后 Registration 到接口上

    public static class IdentityServerServiceFactoryExtensions
        {
            public static void RegisterOperationalServices(this IdentityServerServiceFactory factory, EntityFrameworkServiceOptions options)
            {
                if (factory == null) throw new ArgumentNullException("factory");
                if (options == null) throw new ArgumentNullException("options");
    
                factory.Register(new Registration<IOperationalDbContext>(resolver => new OperationalDbContext(options.ConnectionString, options.Schema)));
                factory.AuthorizationCodeStore = new Registration<IAuthorizationCodeStore, AuthorizationCodeStore>();
                factory.TokenHandleStore = new Registration<ITokenHandleStore, TokenHandleStore>();
                factory.ConsentStore = new Registration<IConsentStore, ConsentStore>();
                factory.RefreshTokenStore = new Registration<IRefreshTokenStore, RefreshTokenStore>();
            }
    
            public static void RegisterConfigurationServices(this IdentityServerServiceFactory factory, EntityFrameworkServiceOptions options)
            {
                factory.RegisterClientStore(options);
                factory.RegisterScopeStore(options);
            }
    
            public static void RegisterClientStore(this IdentityServerServiceFactory factory, EntityFrameworkServiceOptions options)
            {
                if (factory == null) throw new ArgumentNullException("factory");
                if (options == null) throw new ArgumentNullException("options");
    
                factory.Register(new Registration<IClientConfigurationDbContext>(resolver => new ClientConfigurationDbContext(options.ConnectionString, options.Schema)));
                factory.ClientStore = new Registration<IClientStore, ClientStore>();
                factory.CorsPolicyService = new ClientConfigurationCorsPolicyRegistration(options);
            }
            
            public static void RegisterScopeStore(this IdentityServerServiceFactory factory, EntityFrameworkServiceOptions options)
            {
                if (factory == null) throw new ArgumentNullException("factory");
                if (options == null) throw new ArgumentNullException("options");
    
                factory.Register(new Registration<IScopeConfigurationDbContext>(resolver => new ScopeConfigurationDbContext(options.ConnectionString, options.Schema)));
                factory.ScopeStore = new Registration<IScopeStore, ScopeStore>();
            }
        }

    TokenCleanup 类负责定时清除过期的票据信息

    public class TokenCleanup
        {
            private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();
    
            EntityFrameworkServiceOptions options;
            CancellationTokenSource source;
            TimeSpan interval;
    
            public TokenCleanup(EntityFrameworkServiceOptions options, int interval = 60)
            {
                if (options == null) throw new ArgumentNullException("options");
                if (interval < 1) throw new ArgumentException("interval must be more than 1 second");
    
                this.options = options;
                this.interval = TimeSpan.FromSeconds(interval);
            }
    
            public void Start()
            {
                if (source != null) throw new InvalidOperationException("Already started. Call Stop first.");
                
                source = new CancellationTokenSource();
                Task.Factory.StartNew(()=>Start(source.Token));
            }
            
            public void Stop()
            {
                if (source == null) throw new InvalidOperationException("Not started. Call Start first.");
    
                source.Cancel();
                source = null;
            }
    
            public async Task Start(CancellationToken cancellationToken)
            {
                while (true)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        Logger.Info("CancellationRequested");
                        break;
                    }
    
                    try
                    {
                        await Task.Delay(interval, cancellationToken);
                    }
                    catch
                    {
                        Logger.Info("Task.Delay exception. exiting.");
                        break;
                    }
    
                    if (cancellationToken.IsCancellationRequested)
                    {
                        Logger.Info("CancellationRequested");
                        break;
                    }
    
                    await ClearTokens();
                }
            }
    
            public virtual IOperationalDbContext CreateOperationalDbContext()
            {
                return new OperationalDbContext(options.ConnectionString, options.Schema);
            }
    
            private async Task ClearTokens()
            {
                try
                {
                    Logger.Info("Clearing tokens");
                    using (var db = CreateOperationalDbContext())
                    {
                        var query =
                            from token in db.Tokens
                            where token.Expiry < DateTimeOffset.UtcNow
                            select token;
    
                        db.Tokens.RemoveRange(query);
    
                        await db.SaveChangesAsync();
                    }
                }
                catch(Exception ex)
                {
                    Logger.ErrorException("Exception cleaning tokens", ex);
                }
            }
        }

    配置Idsv授权服务

    Startup 类

     public class Startup
        {
            /// <summary>
            /// 配置Idsv授权服务
            /// </summary>
            /// <param name="app"></param>
            public void Configuration(IAppBuilder app)
            {
                #region OAuth 2.0 服务端初始化
                //配置EF
                var ef = new EntityFrameworkServiceOptions
                {
                    ConnectionString = DbSetting.OAuth2,
                };
    
                var factory = new IdentityServerServiceFactory();
                //注册Client与Scope的实现
                factory.RegisterConfigurationServices(ef);
                //注册Token实现
                factory.RegisterOperationalServices(ef);
                //自定义用户服务
                factory.UserService = new Registration<IUserService>(resolver => AutofacDependencyResolver.Current.RequestLifetimeScope.Resolve<IdSvrUserService>());
                //自定义视图
                factory.ViewService = new Registration<IViewService, IdSvrMvcViewService<LoginController>>();
    
                factory.Register(new Registration<HttpContext>(resolver => HttpContext.Current));
                factory.Register(new Registration<HttpContextBase>(resolver => new HttpContextWrapper(resolver.Resolve<HttpContext>())));
                //注册Request
                factory.Register(new Registration<HttpRequestBase>(resolver => resolver.Resolve<HttpContextBase>().Request));
                //注册Response
                factory.Register(new Registration<HttpResponseBase>(resolver => resolver.Resolve<HttpContextBase>().Response));
                factory.Register(new Registration<HttpServerUtilityBase>(resolver => resolver.Resolve<HttpContextBase>().Server));
                //注册Session
                factory.Register(new Registration<HttpSessionStateBase>(resolver => resolver.Resolve<HttpContextBase>().Session));
    
                /*
                 //注册 Redis 服务
                factory.Register(new Registration<IDatabaseAsync>(resolver => ConnectionMultiplexer.Connect(CacheSetting.Redis).GetDatabase()));
                factory.AuthorizationCodeStore = new Registration<IAuthorizationCodeStore, IdentityServer3.Contrib.RedisStore.Stores.AuthorizationCodeStore>();
                factory.TokenHandleStore = new Registration<ITokenHandleStore, IdentityServer3.Contrib.RedisStore.Stores.TokenHandleStore>();
                factory.RefreshTokenStore = new Registration<IRefreshTokenStore, IdentityServer3.Contrib.RedisStore.Stores.RefreshTokenStore>();
               */
    
                /*
                    //客户端信息缓存
                    var clientStoreCache = new ClientStoreCache(redis);
                    //作用域信息缓存
                    var scopeStoreCache = new ScopeStoreCache(redis);
                    //用户信息缓存
                    var userServiceCache = new UserServiceCache(redis);
                    //注册客户端缓存-
                    factory.ConfigureClientStoreCache(new Registration<ICache<Client>>(clientStoreCache));
                    //注册作用域缓存
                    factory.ConfigureScopeStoreCache(new Registration<ICache<IEnumerable<Scope>>>(scopeStoreCache));
                    //注册用户缓存
                    // factory.ConfigureUserServiceCache(new Registration<ICache<IEnumerable<Claim>>>(userServiceCache));
                    // factory.ConfigureUserServiceCache(TimeSpan.FromMilliseconds(1000 * 10));
                 */
    
                //Idsv 配置
                app.UseIdentityServer(new IdentityServerOptions
                {
                    SiteName = "Embedded Homeinns PMS 2.0 OAuth2 Service",
                    EnableWelcomePage = true,
                    Factory = factory,
                    RequireSsl = Constants.RequireSsl,
                    PublicOrigin = Constants.PublicOrigin,
                    LoggingOptions = new LoggingOptions()
                    {
                        EnableHttpLogging = true,
                        // EnableKatanaLogging = true,
                        // EnableWebApiDiagnostics = true,
                        // WebApiDiagnosticsIsVerbose = true,
                    },
                    SigningCertificate = new X509Certificate2(string.Format(@"{0}IdSvridsrv3test.pfx", AppDomain.CurrentDomain.BaseDirectory), "idsrv3test"),
                    EventsOptions = new EventsOptions
                    {
                        RaiseSuccessEvents = true,
                        RaiseErrorEvents = true,
                        RaiseFailureEvents = true,
                        RaiseInformationEvents = true,
                    },
                    CspOptions = new CspOptions
                    {
                        Enabled = false,
                    },
                    AuthenticationOptions = new AuthenticationOptions
                    {
                        CookieOptions = new IdentityServer3.Core.Configuration.CookieOptions
                        {
                            SlidingExpiration = true,
                        },
                        EnablePostSignOutAutoRedirect = true,
                        EnableLocalLogin = true,
                        EnableSignOutPrompt = false
                    }
                });
                //启动清除过期票据定时器
                var cleanToken = new TokenCleanup(ef, 20);
                cleanToken.Start();
                #endregion
    
                #region OAuth 2.0 管理后台 初始化
                /*
                //管理员功能 初始化
                app.Map("/admin", adminApp =>
                {
                    var factoryAdmin = new IdentityAdmin.Configuration.IdentityAdminServiceFactory();
                    //注入配置
                    factoryAdmin.Configure();
                    //注册管理员
                    adminApp.UseIdentityAdmin(new IdentityAdmin.Configuration.IdentityAdminOptions
                    {
                        Factory = factoryAdmin,
                        //AdminSecurityConfiguration =
                    });
                });
                 */
                #endregion 
            }
        }

     客户端模式问题

    • 客户端,作用域,票据的持久化 [OK]
    • 限制客户端每天获得新票据的次数
    • 票据过期删除的策略 [OK]
    • 授权服务器客户端信息缓存策略 [OK]
    • 资源服务器票据验证的缓存策略 [OK]
    • 作用域权限范围控制
    • ClientId 与 ClientSecret 的生成规则 [OK]
    • 密码模式用户的身份验证 https://github.com/IdentityServer/IdentityServer3.AspNetIdentity

    REFER:
    Deployment
    https://identityserver.github.io/Documentation/docsv2/advanced/deployment.html

  • 相关阅读:
    方法指针或非指针类型接收器
    error接口
    17、想要回到项目上一版本,或者指定版本时,如何进行操作?
    08、想要找到所有操作记录时,如何操作
    16、不再追踪时,如何实现撤销追踪操作
    1月19日a
    1月18日
    1月20日
    1月25
    1月17日
  • 原文地址:https://www.cnblogs.com/Irving/p/5788285.html
Copyright © 2020-2023  润新知