专业网站建设品牌,十四年专业建站经验,服务6000+客户--广州京杭网络
免费热线:400-683-0016      微信咨询  |  联系我们

IdentityServer4授权和认证对接数据库

当前位置:网站建设 > 技术支持
资料来源:网络整理       时间:2023/2/14 0:44:13       共计:3590 浏览

我们之前都是用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 Date\Migrations\IdentityServer\ConfiguragtionDb
 Add-Migration InitConfiguration -Context PersistedGrantDbContext -o Date\Migrations\IdentityServer\PersistedGrantDb
这样就添加了两个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

 
版权说明:
本网站凡注明“广州京杭 原创”的皆为本站原创文章,如需转载请注明出处!
本网转载皆注明出处,遵循行业规范,如发现作品内容版权或其它问题的,请与我们联系处理!
欢迎扫描右侧微信二维码与我们联系。
·上一条:IdentityServer4实现单点登录统一认证 | ·下一条:.Net Core 数据库的迁移

Copyright © 广州京杭网络科技有限公司 2005-2025 版权所有    粤ICP备16019765号 

广州京杭网络科技有限公司 版权所有