最近花了一點時間,閱讀了IdentityServer的源碼,大體瞭解項目總體的抽象思惟、面向對象的重要性; 生產環境若是要使用 IdentityServer3 ,主要涉及受權服務,資源服務的部署負載的問題,客戶端(clients),做用域(scopes),票據(token)必定都要持久化, 客戶端與做用域的持久化只須要實現 IClientStore 與 IScopeStore 的接口,能夠本身實現,也能夠直接使用 IdentityServer3 自身的擴展 IdentityServer3.EntityFramework 。html
核心類庫
Install-Package IdentityServer3
IdentityServer 核心庫,只支持基於內存的客戶端信息與用戶信息配置git
配置信息持久化
客戶端,做用域,票據的持久化 ,支持的擴展有兩個,一個基於 EF,另一個使用MongoDb(社區支持)
Install-Package IdentityServer3.EntityFramework
Install-Package IdentityServer.v3.MongoDbgithub
用戶持久化redis
用戶的持久化支持 MembershipReboot 與 ASP.NET Identity 兩種
Install-Package IdentityServer3.MembershipReboot
Install-Package IdentityServer3.AspNetIdentitysql
其餘插件數據庫
WS-Federation
Install-Package IdentityServer3.WsFederation
Access token validation middleware(驗證中間件)
Install-Package IdentityServer3.AccessTokenValidation緩存
國際化服務器
https://github.com/johnkors/IdentityServer3.Contrib.Localizationapp
緩存async
https://github.com/AliBazzi/IdentityServer3.Contrib.RedisStore
客戶端
https://github.com/IdentityModel/IdentityModel2
客戶端(clients)與做用域(scopes)的持久化
客戶端與做用域的持久化只須要實現 IClientStore 與 IScopeStore 的接口,默認EF 在 IdentityServerServiceFactory 實現了 RegisterClientStore 與 RegisterScopeStore 兩個擴展方法,也能夠使用 RegisterConfigurationServices 方法,默認包含以上兩個擴展方法合集;RegisterOperationalServices 擴展方法實現 IAuthorizationCodeStore, ITokenHandleStore, IRefreshTokenStore, and IConsentStore 功能等。
能夠在 IdentityServer3.EntityFramework 的項目中找到數據庫的初始SQL ,
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); } } }
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}\IdSvr\idsrv3test.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 } }
客戶端模式問題
REFER:
Deployment
https://identityserver.github.io/Documentation/docsv2/advanced/deployment.html