これまでに分かったことを書きます。
ISecurityTokenValidatorインターフェースを実装します。
C#
1 using System ;
2 using System . Linq ;
3 using System . Security . Claims ;
4 using Microsoft . AspNetCore . Identity ;
5 using Microsoft . IdentityModel . Tokens ;
6 using Microsoft . Extensions . DependencyInjection ;
7 using SpaRoleAuthExp . Areas . Identity . Data ;
8 using System . IdentityModel . Tokens . Jwt ;
9
10 namespace SpaRoleAuthExp . Auth
11 {
12 public class MySecurityTokenValidator : ISecurityTokenValidator
13 {
14 public bool CanValidateToken = > true ;
15
16 public int MaximumTokenSizeInBytes { get ; set ; } = TokenValidationParameters . DefaultMaximumTokenSizeInBytes ;
17
18 private IServiceProvider _serviceProvider { get ; }
19
20 private JwtSecurityTokenHandler _tokenHandler { get ; }
21
22 public MySecurityTokenValidator ( IServiceProvider serviceProvider )
23 {
24 _serviceProvider = serviceProvider ;
25 _tokenHandler = new JwtSecurityTokenHandler ( ) ;
26 }
27
28 public bool CanReadToken ( string securityToken )
29 {
30 return _tokenHandler . CanReadToken ( securityToken ) ;
31 }
32
33 public ClaimsPrincipal ValidateToken ( string securityToken , TokenValidationParameters validationParameters , out SecurityToken validatedToken )
34 {
35 // クライアントから受け取ったトークンから、ClaimsPrincipal(と SecurityToken vt)を作る
36 var cp = _tokenHandler . ValidateToken ( securityToken , validationParameters , out var vt ) ;
37
38 var userManager = _serviceProvider . GetService < UserManager < ApplicationUser >> ( ) ;
39 // (1)そのClaimsPrincipalで、DBからユーザを取得する。※このとき、GetUserAsync(cp)メソッドだとログイン中のユーザを削除していても何故かユーザーを取得できる
40 var applicationUser = userManager . FindByNameAsync ( cp . Identity . Name ) . Result ;
41
42 if ( applicationUser == null )
43 {
44 validatedToken = null ;
45 return new ClaimsPrincipal ( ) ; // これによりクライアントにHTTPステータス401を応答する。※ここでnullを返すと例外が発生する。
46 }
47
48 var principalFactory = _serviceProvider . GetService < IUserClaimsPrincipalFactory < ApplicationUser >> ( ) ;
49 // 現在のDB内のユーザからClaimsPrincipalを作る
50 var claimsPrincipal = principalFactory . CreateAsync ( applicationUser ) . Result ;
51 // DBからユーザのロールを取得する
52 var roles = userManager . GetRolesAsync ( applicationUser ) . Result ;
53 // ClaimsPrincipalにロールを追加する
54 var claims = roles . Select ( role = > new Claim ( ClaimTypes . Role , role ) ) ;
55 claimsPrincipal . AddIdentity ( new ClaimsIdentity ( claims ) ) ;
56
57 validatedToken = vt ; // 最初に作ったSecurityTokenを返す
58 return claimsPrincipal ; // 現在のDB内のユーザ情報(ロール含む)から作ったClaimsPrincipalを返す
59 }
60 }
61 }
そして、StartupのConfigureServicesメソッド内で、MySecurityTokenValidatorを登録します。
C#
1 public void ConfigureServices ( IServiceCollection services )
2 {
3 //・・・省略・・・
4 services . AddAuthentication ( options = >
5 {
6 options . DefaultAuthenticateScheme = JwtBearerDefaults . AuthenticationScheme ;
7 options . DefaultScheme = JwtBearerDefaults . AuthenticationScheme ;
8 options . DefaultChallengeScheme = JwtBearerDefaults . AuthenticationScheme ;
9 } )
10 . AddJwtBearer ( options = >
11 {
12 options . RequireHttpsMetadata = false ;
13 options . SaveToken = true ;
14 options . TokenValidationParameters = new TokenValidationParameters
15 {
16 ValidateIssuerSigningKey = true ,
17 ValidateIssuer = false ,
18 IssuerSigningKey = new SymmetricSecurityKey ( key ) ,
19 ValidateAudience = false
20 } ;
21 options . SecurityTokenValidators . Clear ( ) ; // これがないと、デフォルトの認証が動く。
22 // カスタマイズしたSecurityTokenValidatorを登録する
23 options . SecurityTokenValidators . Add ( new MySecurityTokenValidator ( services . BuildServiceProvider ( ) ) ) ;
24 } ) ;
25 //・・・省略・・・
26 }
これで実現できましたが、若干疑問もあります。
(1)のところで、userManager.GetUserAsync(cp) とすると、ユーザーを削除していても取得できてしまうところが、どういうカラクリによるものなのか分からず気持ちが悪いです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。