最近花了一点时间,阅读了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 关系项目结构
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 = )
{
if (options == null) throw new ArgumentNullException("options");
if (interval < ) 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}\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, );
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