最近花了一點時間,閱讀了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
配置信息持久化(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 ,
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 類修改
/// <summary> /// OAuth2 服務配置 /// </summary> public class Startup { /// <summary> /// 配置Idsv授權服務 /// </summary> /// <param name="app"></param> public void Configuration(IAppBuilder app) { #region OAuth 2.0 服務端初始化 /* //配置內存的數據持久化到DB Factory = new IdentityServerServiceFactory() .UseInMemoryClients(Clients.Get()) .UseInMemoryScopes(Scopes.Get()) .UseInMemoryUsers(Users.Get()), */ //EF配置 var ef = new EntityFrameworkServiceOptions { ConnectionString = DbSetting.OAuth2, }; var redis = ConnectionMultiplexer.Connect(CacheSetting.Redis); var factory = new IdentityServerServiceFactory(); //注冊Client與Scope的實現 factory.RegisterConfigurationServices(ef); //注冊Token實現 factory.RegisterOperationalServices(ef); /* //注冊用戶(基于用戶表) factory.UseInMemoryUsers(new List<InMemoryUser>() { //測試用戶 new InMemoryUser() { Username = "irving", Password = "123456", Subject = "1", Claims = new[] { new Claim(IdentityServer3.Core.Constants.ClaimTypes.GivenName, "Bob"), new Claim(IdentityServer3.Core.Constants.ClaimTypes.FamilyName, "Smith") } } }); */ //自定義用戶服務 factory.UserService = new Registration<IUserService>(resolver => AutofacDependencyResolver.Current.RequestLifetimeScope.Resolve<IdSvrUserService>()); //自定義頁面 //factory.ViewService = new Registration<IViewService, IdSvrViewService>(); 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>()))); factory.Register(new Registration<HttpRequestBase>(resolver => resolver.Resolve<HttpContextBase>().Request)); factory.Register(new Registration<HttpResponseBase>(resolver => resolver.Resolve<HttpContextBase>().Response)); factory.Register(new Registration<HttpServerUtilityBase>(resolver => resolver.Resolve<HttpContextBase>().Server)); factory.Register(new Registration<HttpSessionStateBase>(resolver => resolver.Resolve<HttpContextBase>().Session)); //Redis 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)); //idsv配置 app.UseIdentityServer(new IdentityServerOptions { SiteName = "Embedded OAuth2 Service", EnableWelcomePage = true, Factory = factory, RequireSsl = false, LoggingOptions = new LoggingOptions(), SigningCertificate = new X509Certificate2(string.Format(@"{0}\identityServer\idsrv3test.pfx", AppDomain.CurrentDomain.BaseDirectory), "idsrv3test"), EventsOptions = new EventsOptions { RaiseSuccessEvents = true, RaiseErrorEvents = true, RaiseFailureEvents = true, RaiseInformationEvents = true } }); //factory.CorsPolicyService = new Registration<ICorsPolicyService>(new DefaultCorsPolicyService { AllowAll = true }); //啟動清除過期票據定時器 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
不含病毒。www.avast.com |
留言列表