identiyt 的使用可以看之前的文章: https://www.cnblogs.com/nsky/p/10323415.html
之前的 ids4 授权服务器都是用的 in-men 方式把数据添加到内存,
现在应该改成 identity 对接数据库操作, 因为之前的代码有, 就不一一创建了
nuget 包: IdentityServer4.AspNetIdentity
那么之前的 TestUser 以及 TestUserStore 都要替换掉
AddAspNetIdentity<ApplicationUser>()
那么 Profile 是什么? Profile 就是用户资料, ids 4 里面定义了一个 IProfileService 的接口用来获取用户的一些信息,
主要是为当前的认证上下文绑定 claims. 我们可以实现 IProfileService 从外部创建 claim 扩展到 ids4 里面.
定义一个 ProfileServices 类继承 IProfileService
- using AuthorizationServer.Models;
- using IdentityModel;
- using IdentityServer4.Models;
- using IdentityServer4.Services;
- using Microsoft.AspNetCore.Identity;
- using System.Collections.Generic;
- using System.Linq;
- using System.Security.Claims;
- using System.Threading.Tasks;
- namespace AuthorizationServer.Services
- {
- /// <summary>
- /// Profile 就是用户资料, ids 4 里面定义了一个 IProfileService 的接口用来获取用户的一些信息
- /// , 主要是为当前的认证上下文绑定 claims. 我们可以实现 IProfileService 从外部创建 claim 扩展到 ids4 里面.
- /// 然后返回
- /// </summary>
- public class ProfileServices : IProfileService
- {
- private readonly UserManager<ApplicationUser> _userManager;
- private readonly RoleManager<ApplicationRole> _roleManager;
- public ProfileServices(
- UserManager<ApplicationUser> userManager,
- RoleManager<ApplicationRole> roleManager)
- {
- _userManager = userManager;
- _roleManager = roleManager;
- }
- public async Task<List<Claim>> GetClaimsFromUserAsync(ApplicationUser user)
- {
- var claims = new List<Claim> {
- new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
- new Claim(JwtClaimTypes.PreferredUserName,user.UserName)
- };
- var role = await _userManager.GetRolesAsync(user);
- role.ToList().ForEach(f =>
- {
- claims.Add(new Claim(JwtClaimTypes.Role, f));
- });
- if(!string.IsNullOrEmpty(user.Avatar))
- {
- claims.Add(new Claim("avatar", user.Avatar));
- }
- claims.Add(new Claim("姓名", "tom"));
- return claims;
- }
- /// <summary>
- /// 获取用户 Claims
- /// 用户请求 userinfo endpoint 时会触发该方法
- /// http://localhost:5003/connect/userinfo
- /// </summary>
- /// <param name="context"></param>
- /// <returns></returns>
- public async Task GetProfileDataAsync(ProfileDataRequestContext context)
- {
- var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
- var user = await _userManager.FindByIdAsync(subjectId);
- context.IssuedClaims =await GetClaimsFromUserAsync(user);
- }
- /// <summary>
- /// 判断用户是否可用
- /// Identity Server 会确定用户是否有效
- /// </summary>
- /// <param name="context"></param>
- /// <returns></returns>
- public async Task IsActiveAsync(IsActiveContext context)
- {
- var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
- var user = await _userManager.FindByIdAsync(subjectId);
- context.IsActive = user != null; // 该用户是否已经激活, 可用, 否则不能接受 token
- /*
- 这样还应该判断用户是否已经锁定, 那么应该 IsActive=false
- */
- }
- }
- }
ConfigureServices 也要修改:
这样的话. 配置基本上就完成了
接下来用 Hybrid Flow 实现试试
因为 CodeIdToken 有 2 种方式返回 profile
ResponseType 改成 code id_token
- options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
- // 设置从 UserInfoEndpoint 获取 claims 信息
- options.GetClaimsFromUserInfoEndpoint = true;
获取后映射到 claims
- options.GetClaimsFromUserInfoEndpoint = true;
- options.ClaimActions.MapJsonKey("sub", "sub");
- options.ClaimActions.MapJsonKey("preferred_username", "preferred_username");
- options.ClaimActions.MapJsonKey("avatar", "avatar");
- options.ClaimActions.MapCustomJson("role", job => job["role"].ToString());
这样会返回的 access_token 信息也包含了该信息,
但如果 claims 过大, 那么 access_token 也会很大
授权成功了. 在 view 页面
引入:@using Microsoft.AspNetCore.Authentication
并获取
这样就会有 ProfileServices.cs 类中获取的 clsims 了
access_token 中同样会有
id_token 中是不会有的
上面说了, profile 的 cliams 信息是通过 access_token 访问 UserInfoEndpoint 获取的
我们也可以通过 postman 试试
而这些信息都是从数据库读取出来的
如果不设置 GetClaimsFromUserInfoEndpoint=true
它默认是 false
那么我们想得到怎么办,
1: 可以自己用 access_token 去获取一次
2: 授权服务器 client 设置 AlwaysIncludeUserClaimsInIdToken=true
这样就会把返回的 profile 信息包含在 idtoken 中, 好像 idtoken 也会有很大的可能
好了. 试试效果, 这样其实 idtoken 和 access_token 都返回了 profile 信息
来源: http://www.bubuko.com/infodetail-2945318.html