asp.net-core – 如何使用带有IdentityServer4的ASP.Net标识添加要包含在access_t
|
如何添加要包含在令牌中的其他声明? 一旦API收到承载令牌,User.Identity对象就会填充以下声明. [
{
"key": "nbf","value": "1484614344"
},{
"key": "exp","value": "1484615244"
},{
"key": "iss","value": "http://localhost:85"
},{
"key": "aud","value": "http://localhost:85/resources"
},"value": "WebAPI"
},{
"key": "client_id","value": "MyClient"
},{
"key": "sub","value": "d74c815a-7ed3-4671-b4e4-faceb0854bf6"
},{
"key": "auth_time","value": "1484611732"
},{
"key": "idp","value": "local"
},{
"key": "role","value": "AccountsManager"
},{
"key": "scope","value": "openid"
},"value": "profile"
},"value": "roles"
},"value": "offline_access"
},{
"key": "amr","value": "pwd"
}
]
我想要其他声明,如用户名,电子邮件,legacySystemUserId等.这些字段已经存在于AspNetUsers表中(并且不会重复存在于AspNetUserClaims表中),并且可以在我的ApplicationUser对象的ASP .Net Core应用程序中使用. 我希望它们包含在使用用户名和密码进行身份验证后返回的访问令牌中.想要在我无法访问身份服务器数据库的WebAPI应用程序中使用相同的内容,而且它自己的数据库根据用户的电子邮件地址而不是UserId存储数据(这是一个在ASP .NET身份中生成的guid并作为SUB索赔). 解决方法几个小时以来我一直在打这个问题,最后拼凑出了解决方案.这个 article是一个很大的帮助,但总结和分享我的实现:为了获得分配给用户的声明并将其附加到访问令牌,您需要在身份服务器上实现两个接口:IResourceOwnerPasswordValidator和IProfileService.以下是我对这两个类的实现,并且是粗略的草稿,但它们有效. **请务必在此时获取最新版本的IdentityServer4 – 1.0.2. public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
private readonly UserManager<ApplicationUser> _userManager;
public ResourceOwnerPasswordValidator(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
var userTask = _userManager.FindByNameAsync(context.UserName);
var user = userTask.Result;
context.Result = new GrantValidationResult(user.Id,"password",null,"local",null);
return Task.FromResult(context.Result);
}
}
和 public class AspNetIdentityProfileService : IProfileService
{
private readonly UserManager<ApplicationUser> _userManager;
public AspNetIdentityProfileService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var subject = context.Subject;
if (subject == null) throw new ArgumentNullException(nameof(context.Subject));
var subjectId = subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(subjectId);
if (user == null)
throw new ArgumentException("Invalid subject identifier");
var claims = await GetClaimsFromUser(user);
var siteIdClaim = claims.SingleOrDefault(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress");
context.IssuedClaims.Add(new Claim(JwtClaimTypes.Email,user.Email));
context.IssuedClaims.Add(new Claim("siteid",siteIdClaim.Value));
context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role,"User"));
var roleClaims = claims.Where(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role");
foreach (var roleClaim in roleClaims)
{
context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role,roleClaim.Value));
}
}
public async Task IsActiveAsync(IsActiveContext context)
{
var subject = context.Subject;
if (subject == null) throw new ArgumentNullException(nameof(context.Subject));
var subjectId = subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(subjectId);
context.IsActive = false;
if (user != null)
{
if (_userManager.SupportsUserSecurityStamp)
{
var security_stamp = subject.Claims.Where(c => c.Type == "security_stamp").Select(c => c.Value).SingleOrDefault();
if (security_stamp != null)
{
var db_security_stamp = await _userManager.GetSecurityStampAsync(user);
if (db_security_stamp != security_stamp)
return;
}
}
context.IsActive =
!user.LockoutEnabled ||
!user.LockoutEnd.HasValue ||
user.LockoutEnd <= DateTime.Now;
}
}
private async Task<IEnumerable<Claim>> GetClaimsFromUser(ApplicationUser user)
{
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Subject,user.Id),new Claim(JwtClaimTypes.PreferredUserName,user.UserName)
};
if (_userManager.SupportsUserEmail)
{
claims.AddRange(new[]
{
new Claim(JwtClaimTypes.Email,user.Email),new Claim(JwtClaimTypes.EmailVerified,user.EmailConfirmed ? "true" : "false",ClaimValueTypes.Boolean)
});
}
if (_userManager.SupportsUserPhoneNumber && !string.IsNullOrWhiteSpace(user.PhoneNumber))
{
claims.AddRange(new[]
{
new Claim(JwtClaimTypes.PhoneNumber,user.PhoneNumber),new Claim(JwtClaimTypes.PhoneNumberVerified,user.PhoneNumberConfirmed ? "true" : "false",ClaimValueTypes.Boolean)
});
}
if (_userManager.SupportsUserClaim)
{
claims.AddRange(await _userManager.GetClaimsAsync(user));
}
if (_userManager.SupportsUserRole)
{
var roles = await _userManager.GetRolesAsync(user);
claims.AddRange(roles.Select(role => new Claim(JwtClaimTypes.Role,role)));
}
return claims;
}
}
一旦你有了这些,他们需要在startup.cs中添加到你的服务: services.AddTransient<IResourceOwnerPasswordValidator,ResourceOwnerPasswordValidator>(); services.AddTransient<IProfileService,AspNetIdentityProfileService>(); 这是我的配置快速查看: public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId()
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource
{
Name = "api1",Description = "My Api",Scopes =
{
new Scope()
{
Name = "api1",DisplayName = "Full access to Api"
}
}
}
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "apiClient",ClientName = "Api Angular2 Client",AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,AlwaysSendClientClaims = true,AlwaysIncludeUserClaimsInIdToken = true,ClientSecrets =
{
new Secret("secret".Sha256())
},AllowedScopes =
{
"api1"
}
}
};
}
之后,从客户端调用身份服务器: var discoTask = DiscoveryClient.GetAsync("http://localhost:5000");
var disco = discoTask.Result;
var tokenClient = new TokenClient(disco.TokenEndpoint,"apiClient","secret");
var tokenResponseTask = tokenClient.RequestResourceOwnerPasswordAsync("user@domain.com","my-password","api1");
var tokenResponse = tokenResponseTask.Result;
var accessToken = tokenResponse.AccessToken;
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return;
}
检查jwt.io上的令牌并查看结果…… (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net – VirtualPathUtility.ToAbsolute()VS. Url.Conte
- 您希望在初学者的ASP.NET安全手册中看到什么?
- asp.net-mvc – ASP.NET MVC:从控制器返回CDN图像
- 如何在ASP.NET自定义控件中持久保存List属性?
- asp.net-ajax – ASP.Net AJAX UpdatePanel无法触发Selecte
- 使用SharpZipLib压缩打包多个内存中的文件
- asp.net – bing地图花钱?
- asp.net-mvc – 在链接文本中使用HTML元素创建一个ActionLi
- asp.net-mvc – User.IsInRole不起作用
- asp.net – 是否可以使用OAuth2来保护“非休息”应用程序
- asp.net-mvc – 在不显眼的验证过程中使用parseJ
- asp.net – 使用web.config进行密码保护的文件夹
- asp.net-mvc-4 – 找不到布局页面
- asp.net – 如何在MVC3中使用https生成绝对URL?
- ASP.NET MVC 3数据注释大于下载日期时间和int
- asp.net – 如何使用jQuery清除DIV中的所有文本框
- asp.net-mvc-4 – ASP .Net MVC 4 Authorize和Al
- asp.net – 如何为Google Chrome启用自动登录用户
- asp.net-mvc – 用户不在角色时的ASP.NET登录重定
- asp.net-mvc-3 – 在IIS 7.5上托管MVC应用程序时
