AspNetCore当中JWT键值映射的问题

当使用JwtBearer库时,对于自定义的键可能出现映射错误的问题

出错情况:当自定义的键出现在此库默认映射的列表当中时,就会出现根据自定义的键找不到值的情况

比如

1
2
3
4
5
6
7
8
9
var authClaim = GetAuthClaims(context.User, RoleKey);

private static string[] GetAuthClaims(ClaimsPrincipal user, string claimType)
{
return user.Claims
.Where(c => c.Type == claimType)
.Select(c => c.Value)
.ToArray();
}

如果RoleKey为"roles"则会自动映射到ClaimTypes.Role,导致此处根据"roles"获取不到值
这个问题只会在.net 8当中遇到,这是.net 8的一个中断性变更

解决方案:禁用掉此库的默认映射的功能

  1. 查看源代码可以发现JwtBearerOptions类中有如下属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
public bool MapInboundClaims
{
get
{
return _mapInboundClaims;
}
set
{
_mapInboundClaims = value;
_defaultHandler.MapInboundClaims = value;
_defaultTokenHandler.MapInboundClaims = value;
}
}

此属性控制自动映射是否生效,将自动映射关闭之后即可实现根据自定义键获取值的功能。
2. 自动映射的实现方式:
主要是一个内部的自动映射类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
internal static class ClaimTypeMapping
{
private static readonly Dictionary<string, string> shortToLongClaimTypeMapping;

private static readonly Dictionary<string, string> longToShortClaimTypeMapping;

private static readonly HashSet<string> inboundClaimFilter;

/// <summary>
/// Gets the InboundClaimTypeMap used by JwtSecurityTokenHandler when producing claims from jwt.
/// </summary>
public static IDictionary<string, string> InboundClaimTypeMap => shortToLongClaimTypeMapping;

/// <summary>
/// Gets the OutboundClaimTypeMap is used by JwtSecurityTokenHandler to shorten claim types when creating a jwt.
/// </summary>
public static IDictionary<string, string> OutboundClaimTypeMap => longToShortClaimTypeMapping;

public static ISet<string> InboundClaimFilter => inboundClaimFilter;

/// <summary>
/// Initializes static members of the <see cref="T:Microsoft.IdentityModel.JsonWebTokens.ClaimTypeMapping" /> class.
/// </summary>
static ClaimTypeMapping()
{
shortToLongClaimTypeMapping = new Dictionary<string, string>
{
{ "actort", "http://schemas.xmlsoap.org/ws/2009/09/identity/claims/actor" },
{ "birthdate", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth" },
{ "email", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" },
{ "family_name", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" },
{ "gender", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/gender" },
{ "given_name", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" },
{ "nameid", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" },
{ "sub", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" },
{ "website", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/webpage" },
{ "unique_name", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" },
{ "oid", "http://schemas.microsoft.com/identity/claims/objectidentifier" },
{ "scp", "http://schemas.microsoft.com/identity/claims/scope" },
{ "tid", "http://schemas.microsoft.com/identity/claims/tenantid" },
{ "acr", "http://schemas.microsoft.com/claims/authnclassreference" },
{ "adfs1email", "http://schemas.xmlsoap.org/claims/EmailAddress" },
{ "adfs1upn", "http://schemas.xmlsoap.org/claims/UPN" },
{ "amr", "http://schemas.microsoft.com/claims/authnmethodsreferences" },
{ "authmethod", "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod" },
{ "certapppolicy", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/applicationpolicy" },
{ "certauthoritykeyidentifier", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/authoritykeyidentifier" },
{ "certbasicconstraints", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/basicconstraints" },
{ "certeku", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/eku" },
{ "certissuer", "http://schemas.microsoft.com/2012/12/certificatecontext/field/issuer" },
{ "certissuername", "http://schemas.microsoft.com/2012/12/certificatecontext/field/issuername" },
{ "certkeyusage", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/keyusage" },
{ "certnotafter", "http://schemas.microsoft.com/2012/12/certificatecontext/field/notafter" },
{ "certnotbefore", "http://schemas.microsoft.com/2012/12/certificatecontext/field/notbefore" },
{ "certpolicy", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/certificatepolicy" },
{ "certpublickey", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/rsa" },
{ "certrawdata", "http://schemas.microsoft.com/2012/12/certificatecontext/field/rawdata" },
{ "certserialnumber", "http://schemas.microsoft.com/ws/2008/06/identity/claims/serialnumber" },
{ "certsignaturealgorithm", "http://schemas.microsoft.com/2012/12/certificatecontext/field/signaturealgorithm" },
{ "certsubject", "http://schemas.microsoft.com/2012/12/certificatecontext/field/subject" },
{ "certsubjectaltname", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/san" },
{ "certsubjectkeyidentifier", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/subjectkeyidentifier" },
{ "certsubjectname", "http://schemas.microsoft.com/2012/12/certificatecontext/field/subjectname" },
{ "certtemplateinformation", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/certificatetemplateinformation" },
{ "certtemplatename", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/certificatetemplatename" },
{ "certthumbprint", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/thumbprint" },
{ "certx509version", "http://schemas.microsoft.com/2012/12/certificatecontext/field/x509version" },
{ "clientapplication", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-application" },
{ "clientip", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-ip" },
{ "clientuseragent", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-user-agent" },
{ "commonname", "http://schemas.xmlsoap.org/claims/CommonName" },
{ "denyonlyprimarygroupsid", "http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarygroupsid" },
{ "denyonlyprimarysid", "http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarysid" },
{ "denyonlysid", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid" },
{ "devicedispname", "http://schemas.microsoft.com/2012/01/devicecontext/claims/displayname" },
{ "deviceid", "http://schemas.microsoft.com/2012/01/devicecontext/claims/identifier" },
{ "deviceismanaged", "http://schemas.microsoft.com/2012/01/devicecontext/claims/ismanaged" },
{ "deviceostype", "http://schemas.microsoft.com/2012/01/devicecontext/claims/ostype" },
{ "deviceosver", "http://schemas.microsoft.com/2012/01/devicecontext/claims/osversion" },
{ "deviceowner", "http://schemas.microsoft.com/2012/01/devicecontext/claims/userowner" },
{ "deviceregid", "http://schemas.microsoft.com/2012/01/devicecontext/claims/registrationid" },
{ "endpointpath", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-endpoint-absolute-path" },
{ "forwardedclientip", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-forwarded-client-ip" },
{ "group", "http://schemas.xmlsoap.org/claims/Group" },
{ "groupsid", "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid" },
{ "idp", "http://schemas.microsoft.com/identity/claims/identityprovider" },
{ "insidecorporatenetwork", "http://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork" },
{ "isregistereduser", "http://schemas.microsoft.com/2012/01/devicecontext/claims/isregistereduser" },
{ "ppid", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" },
{ "primarygroupsid", "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid" },
{ "primarysid", "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid" },
{ "proxy", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy" },
{ "pwdchgurl", "http://schemas.microsoft.com/ws/2012/01/passwordchangeurl" },
{ "pwdexpdays", "http://schemas.microsoft.com/ws/2012/01/passwordexpirationdays" },
{ "pwdexptime", "http://schemas.microsoft.com/ws/2012/01/passwordexpirationtime" },
{ "relyingpartytrustid", "http://schemas.microsoft.com/2012/01/requestcontext/claims/relyingpartytrustid" },
{ "role", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" },
{ "roles", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" },
{ "upn", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" },
{ "winaccountname", "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname" }
};
longToShortClaimTypeMapping = new Dictionary<string, string>();
inboundClaimFilter = (inboundClaimFilter = new HashSet<string>());
foreach (KeyValuePair<string, string> item in shortToLongClaimTypeMapping)
{
if (!longToShortClaimTypeMapping.ContainsKey(item.Value))
{
longToShortClaimTypeMapping.Add(item.Value, item.Key);
}
}
}
}

其定义了会自动进行映射的情况

  1. 解决方案:
    在配置jwt的时候,采用如下程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.MapInboundClaims = false;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtSignKey"] ?? string.Empty)),
};
});

在根据自定义键获取值的时候仍然可以参考上面代码来获取,因为自动映射功能已经关闭。