IdentityServer4 QuckStart 授权与自定义Claims
- 作者: 隔壁老王32549884
- 来源: 51数据库
- 2021-08-10
最近在折腾identityserver4,为了简单,直接使用了官方给的quickstart示例项目作为基础进行搭建。有一说一,为了保护一个api,感觉花费的时间比写一个api还要多。
本文基于asp.net core 3.1, identityserver4 3.1.3。代码皆为关键代码,贴全了太多了。
好不容易跑起来了,最终的任务要落实到授权的工作上来。在api中使用authorize用来限制用户的访问。
[route("api/[controller]")]
[authorize(roles = "administrator")]
[apicontroller]
public class userinfocontroller : controllerbase
{
/// <summary>
/// 无参get请求
/// </summary>
/// <returns></returns>
[httpget()]
[producesresponsetype(typeof(returndata<ienumerable<userinfo>>), status200ok)]
public async task<actionresult> get()
{
var info = new info<userinfo>();
return ok(new returndata<ienumerable<userinfo>>(await info.get()));
}
然而在使用的时候,虽然正确取得授权,但是却无法正常访问api,一直提示401没有授权错误。仔细检查,发现identityserver4返回的内容并没有返回role的jwtclaimtypes,没有它,authorize无法正常工作。
{
"nbf": 1587301921,
"exp": 1587305521,
"iss": "http://localhost:5000",
"aud": "monitoringsystemapi",
"client_id": "webclient",
"sub": "c6c18d4d-c28e-4de5-86dd-779121216204",
"auth_time": 1587301921,
"idp": "local",
"scope": [
"roles",
"monitoringsystemapi",
"offline_access"
],
"amr": [
"pwd"
]
}
实现
查看config.cs,identityserver4默认只返回两种identityresource:openid和profile。按照官方的说法,这个东西定义的内容会返回到用户的token。。那么就果断给它安排。
public static ienumerable<identityresource> ids =>
new list<identityresource>
{
new identityresources.openid(),
new identityresources.profile(),
new identityresource ("roles", new list<string> { jwtclaimtypes.role }){ required = true}
};
public static ienumerable<client> clients =>
new list<client>
{
new client
{
clientid = "webclient",
clientsecrets = { new secret("secret".sha256()) },
allowofflineaccess = true,
allowedgranttypes = granttypes.resourceownerpassword,
// scopes that client has access to
allowedscopes = {
"roles",
"monitoringsystemapi" }
},
执行之前,需要确保数据库中的用户数据,已经包含role的claim。
//添加用户代码
bob = new applicationuser
{
username = "bob"
};
var result = usermgr.createasync(bob, "pass123$").result;
if (!result.succeeded)
{
throw new exception(result.errors.first().description);
}
result = usermgr.addclaimsasync(bob, new claim[]{
new claim(jwtclaimtypes.role, "administrator"),
new claim(jwtclaimtypes.name, "bob smith"),
运行程序,返回值依旧没有任何变化,很挫败,只能继续折腾。
有通过实现iprofileservice达到自定义cliams。文章写的很详细,我这就不重复了,我实际试验过,可以成功。
但是文章末尾的注意,很重要。
“那么, 通过profileservice颁发的claims, 任意clients都能拿到”
说明这个优先级是非常高的,可以覆盖所有的行为,当然我们可以在iprofileservice的实现上对权限进行进一步的设置,不过还是挺麻烦的。,
作为懒人,必然不想再费劲去折腾权限的问题,那么是否有简单点的办法呢?
网上有一些说到了可以通过设置scopes来达到目的。不过过于久远,identityserver4已经没有这个独立的类了,说是已经被apiresource取代了。
直觉上这个东西应该是指示要保护的api的相关内容的,好像和这个没啥关系,不过也只能死马当活马医了。修改config.cs,最终如下内容:
public static ienumerable<apiresource> apis =>
new list<apiresource>
{
new apiresource("pls", new[]{ "role"}),
};
public static ienumerable<client> clients =>
new list<client>
{
new client
{
clientid = "webclient",
clientsecrets = { new secret("secret".sha256()) },
allowofflineaccess = true,
allowedgranttypes = granttypes.resourceownerpassword,
// scopes that client has access to
allowedscopes = {
"pls"
}
},
返回结果如下:
{
"nbf": 1587301799,
"exp": 1587305399,
"iss": "http://localhost:5000",
"aud": "pls",
"client_id": "webclient",
"sub": "c6c18d4d-c28e-4de5-86dd-779121216204",
"auth_time": 1587301799,
"idp": "local",
"role": "administrator",
"scope": [
"pls",
"offline_access"
],
"amr": [
"pwd"
]
}
终于看见心心念念的自定义claim(role),可以去访问api了。
注意,在client中也有个claims,添加了role并且设置
alwayssendclientclaims和alwaysincludeuserclaimsinidtoken之后,会在token中添加client_roie字段,这个是没办法用与授权的,可以理解为identityserver4直接指定了client角色,并不是identity中的角色概念。
后记
回过头来仔细看官方的,apiresource中的userclaims就是用来干这个的,折腾了半天,不如当时仔细看看文档了。
