• 使用Identity Server 4建立Authorization Server (5)


    预备知识: http://www.cnblogs.com/cgzl/p/7746496.html

    第一部分: http://www.cnblogs.com/cgzl/p/7780559.html

    第二部分: http://www.cnblogs.com/cgzl/p/7788636.html

    第三部分: http://www.cnblogs.com/cgzl/p/7793241.html

    第四部分: http://www.cnblogs.com/cgzl/p/7795121.html

    之前的配置都是在内存中, 下面将如何把这些数据存储到Sql Server数据库, 这样更适合生产环境.

    这部分基本完全参考官方文档:

    https://identityserver4.readthedocs.io/en/release/quickstarts/8_entity_framework.html

    安装Entity Framework相关的库

    为Authorization Server 添加 IdentityServer4.EntityFramework:

    还需要安装Microsoft.EntityFrameworkCore.SqlServer:

    最后是Microsoft.EntityFrameworkCore.Tools:

    使用它可以进行迁移等操作.

    然后使用命令行进入Auth Server项目的目录, 试一下dotnet ef命令:

    很不幸, 没找到dotnet ef命令. 这里需要手动修改AuthServer的项目文件, 右键点击项目, 点击Edit AuthServer.csproj.

    这部分操作的官方文档在这: https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet

    我们需要添加这部分代码:

      <ItemGroup>
        <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
      </ItemGroup>

    然后回到命令行, 再执行 dotnet ef:

    这次好用了. 接下来就是add migrations了.

    幸运的是, 之前装的库里面有封装好的model, 它们可以自动创建migration文件.

    这里一共有两个命令(migrations), 一个是为了IdentityServer的配置, 另一个是为了持久化授权.

    dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
    dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb

    运行发现了问题, 这是因为我们还没有配置AuthServer来使用数据库.

    添加appSettings.json, 并指定连接字符串:

    {
      "ConnectionStrings": {
        "DefaultConnection": "Server=(localdb)\mssqllocaldb;Database=AuthServer;Trusted_Connection=True;MultipleActiveResultSets=true"
      },
      "Logging": {
        "IncludeScopes": false,
        "Debug": {
          "LogLevel": {
            "Default": "Warning"
          }
        },
        "Console": {
          "LogLevel": {
            "Default": "Warning"
          }
        }
      }
    }

    修改Startup.cs:

    public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            public void ConfigureServices(IServiceCollection services)
            {
                var connectionString = Configuration.GetConnectionString("DefaultConnection");
                var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
    
                services.AddIdentityServer()
                    // .AddDeveloperSigningCredential()
                    .AddSigningCredential(new X509Certificate2(@"D:Projects	estsocialnetwork.pfx", "Bx@steel"))
                    .AddTestUsers(InMemoryConfiguration.Users().ToList())
                    .AddConfigurationStore(options =>
                    {
                        options.ConfigureDbContext = builder =>
                            builder.UseSqlServer(connectionString,
                                sql => sql.MigrationsAssembly(migrationsAssembly));
                    })
                    // this adds the operational data from DB (codes, tokens, consents)
                    .AddOperationalStore(options =>
                    {
                        options.ConfigureDbContext = builder =>
                            builder.UseSqlServer(connectionString,
                                sql => sql.MigrationsAssembly(migrationsAssembly));
    
                        // this enables automatic token cleanup. this is optional.
                        options.EnableTokenCleanup = true;
                        options.TokenCleanupInterval = 30;
                    });
    
                services.AddMvc();
            }

    首先获取数据库连接字符串, 然后添加两部分配置, 一个是配置数据(clients, resources), 一个是操作数据(tokens, codes, consents同意).

    再次运行命令行:

    dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
    dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb

    好用了.

    看看生成的文件, 是有这两部分:

    看一下文件的内容, 会发现有很多的Table.

    下一步就是添加自动迁移, 暂且在StartUp里面找个位置新建个方法吧:

            private void InitializeDatabase(IApplicationBuilder app)
            {
                using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
                {
                    serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
    
                    var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                    context.Database.Migrate();
                    if (!context.Clients.Any())
                    {
                        foreach (var client in InMemoryConfiguration.Clients())
                        {
                            context.Clients.Add(client.ToEntity());
                        }
                        context.SaveChanges();
                    }
    
                    if (!context.IdentityResources.Any())
                    {
                        foreach (var resource in InMemoryConfiguration.IdentityResources())
                        {
                            context.IdentityResources.Add(resource.ToEntity());
                        }
                        context.SaveChanges();
                    }
    
                    if (!context.ApiResources.Any())
                    {
                        foreach (var resource in InMemoryConfiguration.ApiResources())
                        {
                            context.ApiResources.Add(resource.ToEntity());
                        }
                        context.SaveChanges();
                    }
                }
            }

    首先是分别对两个context进行迁移, 然后判断是否这些表里是空的, 如果没有数据, 就把配置的内存数据添加到数据库里面.

    别忘了在Configure方法调用:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                InitializeDatabase(app);
    
                app.UseDeveloperExceptionPage();
                app.UseIdentityServer();
                app.UseStaticFiles();
                app.UseMvcWithDefaultRoute();
            }

    运行项目, 重新操作一下登陆, 同意的过程, 依然好用.

    看一下数据库:

    确实生成了很多表.

    查看Clients表, 里面有三条数据.

    PersistedGrants里面也有一条数据. 登陆时当你同意请求许可的时候, 就会在这个表里面添加一条数据.

    把用户存储到数据库

    可以使用自定义的用户表来存储用户数据, 但是我要用的是asp.net core identity, 所以我就不讲别的方式了.

    不过首先, 需要重建个项目, 并且把之前讲的所有内容都操作一遍, 因为这里要使用asp.net core mvc 模板并使用Individual User Account的验证方式:

    建立好项目后, 需要把之前讲的所有步骤操作一下, 然后安装: IdentityServer4.AspNetIdentity:

    修改Startup, 大约成为这个样子, 只看红色部分即可:

    namespace AuthorizationServer
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
            
            public void ConfigureServices(IServiceCollection services)
            {
                var connectionString = Configuration.GetConnectionString("DefaultConnection");
                var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
    
                services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(connectionString));
    
                services.AddIdentity<ApplicationUser, IdentityRole>(options =>
                {
                    // Password settings
                    options.Password.RequireDigit = false;
                    options.Password.RequiredLength = 6;
                    options.Password.RequireNonAlphanumeric = false;
                    options.Password.RequireUppercase = false;
                    options.Password.RequireLowercase = false;
                    options.Password.RequiredUniqueChars = 2;
                    // Lockout settings
                    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
                    options.Lockout.MaxFailedAccessAttempts = 5;
                    options.Lockout.AllowedForNewUsers = true;
                    // Signin settings
                    options.SignIn.RequireConfirmedEmail = false;
                    options.SignIn.RequireConfirmedPhoneNumber = false;
                    // User settings
                    options.User.RequireUniqueEmail = false;                
                })
                    .AddEntityFrameworkStores<ApplicationDbContext>()
                    .AddDefaultTokenProviders();
    
                services.AddTransient<IEmailSender, EmailSender>();
                services.AddMvc();
                
                services.AddIdentityServer()
                    .AddDeveloperSigningCredential()
                    // .AddSigningCredential(new X509Certificate2(@"D:Projects	estsocialnetwork.pfx", "password"))
                    .AddConfigurationStore(options =>
                    {
                        options.ConfigureDbContext = builder =>
                            builder.UseSqlServer(connectionString,
                                sql => sql.MigrationsAssembly(migrationsAssembly));
                    })
                    .AddOperationalStore(options =>
                    {
                        options.ConfigureDbContext = builder =>
                            builder.UseSqlServer(connectionString,
                                sql => sql.MigrationsAssembly(migrationsAssembly));
                        options.EnableTokenCleanup = true;
                        options.TokenCleanupInterval = 30;
                    })
                    .AddAspNetIdentity<ApplicationUser>();
            }
            
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                app.InitializeDatabase();
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                    app.UseBrowserLink();
                    app.UseDatabaseErrorPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                app.UseStaticFiles();
                app.UseIdentityServer();
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
        }
    }

    注意在Configure方法里面不要使用app.UseAuthentication(), 因为app.UseIdentityServer()方法已经包含了这个中间件. 然后使用命令行执行:

    dotnet ef database update

    或者在Packge Manager Console执行 update-database也行.

    我照着官方文档操作出现了一些问题, 有几个重复的controller, 因为项目建立好之后有个HomeController和AccountController, 而使用Quickstart UI里面也有这两个Controller.

    所以我最后clone了官方的例子:  https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/6_AspNetIdentity

    修改了一下, 放到了我这个项目里: https://github.com/solenovex/Learning-Identity-Server-4

    其他

    有的项目可能需要使用第三方登陆, 例如使用Google账户, 微软账户, QQ等, 这部分请看官方文档自行学习吧. 我要做的是企业内部项目. 所以这块先不研究了.

    也有可能会使用Auth0, Stormpath这样的OAuth Provider, Auth0我用过, 登陆有点慢, 但功能很强大. 这个也不讲了, 他们的文档写的很好, 也给出了各种客户端的代码, 很容易集成.

    Javascript 客户端

    这将是最后一部分.

    手头的项目有点急.  过几天再写这个.

  • 相关阅读:
    微信小程序在扫一扫进入小程序的时候 安卓手机后台继续运行的常规处理
    在微信小程序上,帮助中心界面实现类似手风琴案例
    使用artTemplate的模板引擎,使用简单
    使用原生JavaScript实现图片预加载,方法简单代码少
    在wepy框架中 使用promise对发送网络请求进行封装 包括post跟get请求
    JavaScript实现按字典排序进行md5加密, 以及个人在小程序也可以实现
    当在微信扫一扫进入小程序 并获取到二维码的参数 从而实现扫码进入小程序
    第九章:看看精彩的世界-使用网络技术
    玉渊潭公园
    军事博物馆
  • 原文地址:https://www.cnblogs.com/cgzl/p/7799567.html
Copyright © 2020-2023  润新知