在项目中自定义集成IdentityService4
OAuth2.0协议
在开始之前呢,需要我们对一些认证授权协议有一定的了解。
OAuth 2.0 的一个简单解释
http://www.ruanyifeng.com/blog/2019/04/oauth_design.html
理解 OAuth 2.0
https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
GitHub OAuth 第三方登录示例教程
http://www.ruanyifeng.com/blog/2019/04/github-oauth.html
IdentityService4 配置说明
当然,前提是我希望你已经对一些官方示例进行了实践,如果没有,下面链接中有中文的案例演示
http://www.identityserver.com.cn/
在官方文档中我们可以在导航栏看到一些配置项,其实常用的只有Client这一项
https://identityserver4.readthedocs.io/en/latest/index.html
开始操作
先简单概述一下我们需要做的事情:
1、存储IdentityService4配置信息
2、存储用户数据 (采用ASP.NET Core Identity)
针对上面两项,官方都有实现,都有针对各自的案例,我们只需要做一个简单的集合,按需集合进项目中。
建立一个空web项目
.NET Core 版本不做要求 3.1、 5.0、 6.0 都可以实现 ,需要注意的是6.0版本的IdentityService4已经没有升级了,有一些Nuget包可能是过时的,当出现时,根据提示改为自己需要的版本即可。
我个人喜欢建立MVC,因为方便,中间件都有,懒得一个个引用了
添加所需NuGet包
Startup.cs文件中注册Identity
// 配置cookie策略 (此配置下方会讲解) builder.Services.Configure<CookiePolicyOptions>(options => { //让IdentityService4框架在http的情况下可以写入cookie options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.Lax; }); //注册Identity //IdentityDB迁移命令 //Add-Migration InitialIAspNetIdentityConfigurationDbMigration -c ApplicationDbContext -o Data/Migrations/AspNetIdentity builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(configuration.GetConnectionString("IdentityDb"), sql => sql.MigrationsAssembly(migrationsAssembly))); builder.Services.AddIdentity<ApplicationUser, ApplicationRole>(options => { //密码配置 options.Password.RequireNonAlphanumeric = false; options.Password.RequireDigit = false; options.Password.RequiredLength = 6; options.Password.RequireUppercase = false; }) .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();
用的是SqlServer,如若使用MySQL替换Nuget包即可,Oracle有点特殊,自行探索,太麻烦就不说了
ApplicationUser 、ApplicationRole 是我自定义扩展Identity的用户和角色,这我就不多说了,用过Identity的都知道
Startup.cs文件中注册IdentityService4
IdentityService4用了两个DbContext,一个存储配置信息,一个存储操作信息
//注册ID4 builder.Services.AddIdentityServer() .AddConfigurationStore(options => { //Add-Migration InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb options.ConfigureDbContext = b => b.UseSqlServer(configuration.GetConnectionString("IdentityDb"), sql => sql.MigrationsAssembly(migrationsAssembly)); }) .AddOperationalStore(options => { //Add-Migration InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb options.ConfigureDbContext = b => b.UseSqlServer(configuration.GetConnectionString("IdentityDb"), sql => sql.MigrationsAssembly(migrationsAssembly)); }) .AddAspNetIdentity<ApplicationUser>() .AddDeveloperSigningCredential(true);
在授权中间件前,引入IdentityService4中间件
数据库迁移
此处需要将Identity的Dbcontext上下文,和IdentityService4的两个DbContext上下文 迁移进数据库中,迁移命令上面已有,执行即可。
//IdentityDB迁移命令 //Add-Migration InitialIAspNetIdentityConfigurationDbMigration -c ApplicationDbContext -o Data/Migrations/AspNetIdentity //Add-Migration InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb //Add-Migration InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
添加自定义所需的页面(登录、注册等)
这些页面来自官方免费的管理UI、或者Identity,代码在源码中,自行拷贝即可
如需其他功能页面,按需从官方Copy即可
添加测试种子数据
此处代码太多,自行去源码查看,讲一下原理:
将IdentityService的Client、Scope等配置信息存储到数据库中 , 初始化用户、角色 信息
编译运行,不报错,成功!
校验一下
在当前项目新增一个Api控制器,返回当前Token所包含的声明信息
注意红色部分,需要我们添加jwt认证
添加Jwt身份认证
我们在上面注册服务时,IS4默认使用的是Cookie认证
所以在添加JwtBearer认证
string identityServerUrl = configuration["Perfect:Identity:Url"]; //当前项目地址 //添加jwt认证方案 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { options.Authority = identityServerUrl; options.RequireHttpsMetadata = false; options.TokenValidationParameters.ValidateAudience = false; options.TokenValidationParameters.ValidateLifetime = true; options.TokenValidationParameters.ClockSkew = TimeSpan.Zero; });
配置swagger认证
先添加一个过滤器
public class SecurityRequirementsOperationFilter : IOperationFilter { /// <summary> /// Add Security Definitions and Requirements /// https://github.com/domaindrivendev/Swashbuckle.AspNetCore#add-security-definitions-and-requirements /// </summary> public void Apply(OpenApiOperation operation, OperationFilterContext context) { bool hasAuthorize = context.MethodInfo.DeclaringType?.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() == true || context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any(); bool hasAllowAnonymous = context.MethodInfo.DeclaringType?.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any() == true || context.MethodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any(); if (hasAuthorize && !hasAllowAnonymous) { operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" }); operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" }); OpenApiSecurityScheme oAuthScheme = new OpenApiSecurityScheme() { Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }; operation.Security = new List<OpenApiSecurityRequirement> { new OpenApiSecurityRequirement { [oAuthScheme] =new []{ "Perfect.Api" } } }; } } }
在Startup中注册,客户端ID、和客户端密钥 来自步骤 “添加测试种子数据” 中
//configuration["xx"]是来自配置文件的取值 //添加Swagger文档 services.AddSwaggerGen(c => { c.SwaggerDoc(configuration["Perfect:Swagger:Name"], new OpenApiInfo { Title = configuration["Perfect:Swagger:Title"], Version = configuration["Perfect:Swagger:Version"], Description = configuration["Perfect:Swagger:Description"], Contact = new OpenApiContact { Name = configuration["Perfect:Swagger:Contact:Name"], Email = configuration["Perfect:Swagger:Contact:Email"] } }); c.OperationFilter<SecurityRequirementsOperationFilter>(); c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, Flows = new OpenApiOAuthFlows { AuthorizationCode = new OpenApiOAuthFlow { AuthorizationUrl = new Uri($"{identityServerUrl}/connect/authorize"), TokenUrl = new Uri($"{identityServerUrl}/connect/token"), Scopes = new Dictionary<string, string> { { "openapi", "接口访问权限" }, } } } }); });
在中间件管道中使用
app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint(string.Format("/swagger/{0}/swagger.json", configuration["Perfect:Swagger:Name"]), configuration["Perfect:Swagger:Title"]); c.OAuthClientId(configuration["Perfect:Swagger:ClientId"]); c.OAuthClientSecret(configuration["Perfect:Swagger:ClientSecret"]); c.OAuthAppName(configuration["Perfect:Swagger:AppName"]); c.OAuthUsePkce(); });
编译运行,打开swagger页面
源码地址:https://github.com/dreamdocker/zerostack
以上教学来自零度课堂,本人只是分享,无其他意义,开会员记得找我哦!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)