• IdentityServer4授权和认证对接数据库


    接着上一篇讲:https://www.cnblogs.com/nsky/p/10352678.html

    我们之前都是用in-men的方式把数据添加到内存了,目的是为了测试方便,

    现在我们把所有配置都添加到数据库中

    用IdeneityServer4 + EntityFramework + ASP.NET Identity的方式

    上篇已经讲过identity和profile的对接,这里讲讲配置信息

    之前都是这样做的

    添加包:IdentityServer4.EntityFramework

    里面有专门的2个DbContext管理对应的信息

    分别是:PersistedGrantDbContext 和 ConfigurationDbContext

    如果还记得Identity,里面有个ApplicationDbContext

    所以这里总共有3个DbContext

    ApplicationDbContext
    PersistedGrantDbContext
    ConfigurationDbContext

    ApplicationDbContext - 负责涉及ASP.NET Identity的用户所以表
    dbo.AspNetRoleClaims
    dbo.AspNetRoles
    dbo.AspNetUserClaims
    dbo.AspNetUserLogins
    dbo.AspNetUserRoles
    dbo.AspNetUsers
    dbo.AspNetUserTokens

    PersistedGrantDbContext - 负责存储同意,授权代码,刷新令牌和引用令牌
    dbo.PersistedGrants

    ConfigurationDbContext - 负责数据库中剩余的所有其他内容

    所以关于迁移,如果我更新任何AspNet Identity模型(即ApplicationUser),那么我将在ApplicationDbContext上运行迁移。

    任何客户端表或其他范围都将在ConfigurationDbContext上运行。并且访问entites(或表)将是相应的上下文。

    添加包之后,添加依赖注入配置

     .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = builder =>
                    {
                        builder.UseSqlServer(Configuration.GetConnectionString("conn"),
                            sql => sql.MigrationsAssembly(migrationAssembly));
                    };
                })
    
                /*
                 这里存储的是,给用户授权的token和一些授权信息  
                 添加来自数据库的操作数据(codes, tokens, consents)
                 */
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = builder =>
                    {
                        builder.UseSqlServer(Configuration.GetConnectionString("conn"),
                            sql => sql.MigrationsAssembly(migrationAssembly));
                    };
                })
    migrationAssembly是当前程序集;
     var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

    接下来生成migration,在项目的程序包管理控制台输入:
     Add-Migration InitConfiguration  -Context ConfigurationDbContext -o DateMigrationsIdentityServerConfiguragtionDb
     Add-Migration InitConfiguration -Context PersistedGrantDbContext -o DateMigrationsIdentityServerPersistedGrantDb
    这样就添加了两个migration
    执行update-database生成表
    update-database -context ConfigurationDbContext

    Update-Database -Context PersistedGrantDbContext
    这样就生成了表


    因为现在还没有界面录入,可以先手动初始化配置文件 到数据库,因为之前有config.cs
    可以直接映射到model写入数据库
      /// <summary>
            /// 因为现在没有通过UI去录入api,client等信息
            /// 所有可以先init一些默认信息写入数据库
            /// </summary>
            /// <param name="app"></param>
            public void InitIdentityServerDataBase(IApplicationBuilder app)
            {
                //ApplicationServices返回的就是IServiceProvider,依赖注入的容器
                using (var scope = app.ApplicationServices.CreateScope())
                {
                    //Update-Database
                    scope.ServiceProvider.GetService<PersistedGrantDbContext>().Database.Migrate();
    
                    //var provide = scope.ServiceProvider.GetService<PersistedGrantDbContext>();
                    //ckk.PersistedGrants.Add(new IdentityServer4.EntityFramework.Entities.PersistedGrant {
    
                    //});
    
                    var configurationDbContext = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
    
                    /*
                     如果不走这个,
                     那么应该手动执行 Update-Database -Context PersistedGrantDbContext
                     */
                    configurationDbContext.Database.Migrate();
    
                    if (!configurationDbContext.Clients.Any())
                    {
                        foreach (var client in Config.GetClients())
                        {
                            //client.ToEntity() 会把当前实体映射到EF实体
                            configurationDbContext.Clients.Add(client.ToEntity());
                        }
                        configurationDbContext.SaveChanges();
                    }
                    if (!configurationDbContext.ApiResources.Any())
                    {
                        foreach (var api in Config.GetApiResources())
                        {
                            configurationDbContext.ApiResources.Add(api.ToEntity());
                        }
                        configurationDbContext.SaveChanges();
                    }
                    if (!configurationDbContext.IdentityResources.Any())
                    {
                        foreach (var identity in Config.GetIdentityResource())
                        {
                            configurationDbContext.IdentityResources.Add(identity.ToEntity());
                        }
                        configurationDbContext.SaveChanges();
                    }
                }
            }
    
    

    在Configure中调用

    InitIdentityServerDataBase(app);

    dotnet run就有数据了

    客户端不用配置,

    获取refresh_token,混合模式是支持refresh_token的

    详情:https://www.cnblogs.com/jesse2013/p/oidc-in-aspnetcore-with-identity-server.html

    IdentityResource新增offline_access身份

     AllowedScopes可以不用加: IdentityServerConstants.StandardScopes.OfflineAccess

    服务端Client设置允许: AllowOfflineAccess = true,
    客户端配置:options.Scope.Add("offline_access");



    拿到这个refresh_token,可以刷新access_token

    一个refresh_token只能用一次,否则:
    通过这个access_token就看访问资源api了
    但就算授权了。也只能访问授权的api
    identityResurce是资源信息,AllowedScopes设置了
    IdentityServerConstants.StandardScopes.OpenId,
    IdentityServerConstants.StandardScopes.Email,
    IdentityServerConstants.StandardScopes.Profile,

    就会返回这些信息,
    OpenId是必须要的,因为OIDC要通过openid确认身份

    Profile是可选的,只是客户端默认是传了Profile的,
    因为oidc就是为了返回用信息而来的

    Profile包含了一些基本的信息
    name
    family_name
    given_name
    middle_name
    nickname
    preferred_username
    profile
    picture
    website
    gender
    birthdate
    zoneinfo
    locale
    updated_at

    Email包含了email 和 email_verified
    这些从源码可以看到:
    https://github.com/IdentityServer/IdentityServer4/blob/63a50d7838af25896fbf836ea4e4f37b5e179cd8/src/Constants.cs


    所以客户端获取的cliams是这些

     因为profile是在我们的ProfileServices类返回的

    那么如果用户没有选择



    是不是应该不返回profile信息呢?

    GetProfileDataAsync方法的context可以拿到当前请求的IdentityResources和ApiResource

    好像通过 var claimTypes = context.RequestedClaimTypes;也可以判断,选择了profile,那么RequestedClaimTypes是有值的

    当然除了了一些基本信息外,客户端还想获取其他资源,这也是可以的

    比如资源服务器有个接口,获取额外的信息,scope叫:OtherInfo




    客户端请求scope:options.Scope.Add("OtherInfo");

    可以看到上面是身份信息,就是会返回的的用户信息

    下面是权限,就是可以去资源服务器获取的那些权限,因为:access toke管的是权限

    1:先不选择,拿到的access_token里面的scope是没有OtherInfo的

    这里为啥有两个offline_access?我也不知道

    2:如果选择的话。如果不出错的话是有的

     

     那么资源服务器就可以根据当前这个scope来判断了

     [HttpGet]
            public ActionResult GetOtherInfo()
            {
                //判断是否授权
                var scope = User.Claims.FirstOrDefault(f => f.Type == "scope" && f.Value == "OtherInfo");
                if (scope != null)
                {
                    return new JsonResult(
                        new
                        {
                            phone = "110",
                            address = "china",
                            age = "20",
                            gender = "m",
                            hobby = "coding"
                        }
                        );
                }
                else //禁止访问
                {
                    return BadRequest(StatusCodes.Status403Forbidden);
                }
            }

    如果授权请求了OtherInfo请求是成功了


    当没有授权OtherInfo的时候,当然,返回什么信息你可以自己定义

    这说明你只有权限访问资源服务器,授权了的api。

    如果你的access_token是错误的。就说明你没有授权,你都没有机会进入api,会提示401

    或者写一个过滤器,弄个接口规范,获取某些参数进行判断

     目前我想到的方法就是这样,也许不是最好的

    既然access_token包含profile信息,它又是JWT类型,那是不是可以DeCode呢?

    答案是可以的:

    界面输出

     源码:https://github.com/byniqing/OAuth2Authorization

    参考:https://cloud.tencent.com/developer/article/1048128





  • 相关阅读:
    ABP记录被删除调用Repository.Get报错
    C# 中在对象后面跟“?” 以及在类型后面跟问号
    list转table
    ling groupby多字段分组统计
    linq一堆多再对多
    ABP下mvc的libs还原
    EF数据迁移
    ABP密码规则设置
    ABP中table时间格式化
    ABP读取appseting.json
  • 原文地址:https://www.cnblogs.com/nsky/p/10353723.html
Copyright © 2020-2023  润新知