• 在项目中自定义集成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

    以上教学来自零度课堂,本人只是分享,无其他意义,开会员记得找我哦!

  • 相关阅读:
    Android开发实例关键点讲解系列之一:Eclipse中建立Android工程
    类欧几里得小记
    【清华集训2017模拟12.09】塔
    【51nod1792】Jabby's segment tree
    【51nod1220】约数之和
    【51nod 2026】Gcd and Lcm
    【JZOJ5180】【NOI2017模拟6.29】呵呵
    2017noip总结
    2017.11.7总结
    Codeforces Round #395 Div.1 C pacifist【JZOJ5449】Pacifist
  • 原文地址:https://www.cnblogs.com/queque/p/16326873.html
Copyright © 2020-2023  润新知