#2까지 진행하고 계정 가입을 했다면 현재 User 롤을 가진 계정이므로 Admin 롤 페이지에는 접근할 수 없다. 근데 만약 User와 Admin 롤이나 여러 롤들을 허용하는 페이지가 있다면?

 

@attribute [Authorize(Roles = "Admin, User")]

 

위와 같이 해주면 된다. 롤이 여러 개면 뭐 다 넣어주면 되지... 그럼 관리는?

 

그래서 간단하게라도 정책(Policy)을 사용하는 것이 편리하다. (정책을 거지 같이 세우면 편리하지 않다...)

 

방법은 매우 쉽다.

 

<Startup.cs>

1
2
3
4
services.AddAuthorization(options =>
{
    options.AddPolicy("IsSuper", policy => policy.RequireRole("Admin""User"));
});
cs

IsSuper 정책을 Admin과 User 모두 해당되게 묶는다. 그리고 지난번과 같이 Pages/FetchData.razor 상단에 다음을 추가하자.

 

@attribute [Authorize(Policy = "IsSuper")]

 

이제 FetchData 페이지는 Admin 그리고 User만 볼 수 있다.

개인적으로 롤이 10개 정도되고 롤에 따라 묶인 정책이 여러 개라서 매우 편리하게 쓰고 있다.

 

만약 좀 더 확장되게 쓰고 싶다면 AuthorizationHandler를 이용해서 핸들링하고 AddPolicy 하면 된다.

이때 policay.RequireRole을 사용하지말고 policy.Requirements.Add를 사용한다. 자세한건 아래 링크.

 

 

ASP.NET Core에서 정책 기반 권한 부여

ASP.NET Core 앱에서 권한 부여 요구 사항을 적용 하기 위한 권한 부여 정책 처리기를 만들고 사용 하는 방법에 대해 알아봅니다.

docs.microsoft.com

이어서 UserClaimsPrincipalFactory를 통해 Claim을 추가하고 우측 상단에 #1에서 추가했던 RealName이 나오도록 해보자.

 

<ApplicationUser.cs>

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
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Security.Claims;
using System.Threading.Tasks;
 
namespace [프로젝트명].Models
{
    public class ApplicationUser : IdentityUser<long>
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public DateTime Created { get; set; }
 
        [Required]
        [Column(TypeName = "CHAR(30)")]
        public string RealName { get; set; }
    }
 
    public class ApplicationUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole<long>>
    {
        public ApplicationUserClaimsPrincipalFactory(
            UserManager<ApplicationUser> userManager,
            RoleManager<IdentityRole<long>> roleManager,
            IOptions<IdentityOptions> optionsAccessor)
            : base(userManager, roleManager, optionsAccessor)
        {
        }
 
        protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
        {
            var identity = await base.GenerateClaimsAsync(user);
            identity.AddClaim(new Claim("RealName", user.RealName));
            return identity;
        }
    }
}
 
cs

ApplicationUser는 기존과 변화없고 UserClaimsPrincipalFactory의 GenerateClaimsAsync를 재정의하여 RealName을 추가해 준다.

 

<Startup.cs>

1
2
3
4
services.AddIdentity<ApplicationUser, IdentityRole<long>>()
    .AddDefaultUI()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddClaimsPrincipalFactory<ApplicationUserClaimsPrincipalFactory>();
cs

Startup.cs에서 AddIdentity 부분을 위와 같이 수정하면 끝!

이렇게 추가된 Claim은 아래와 같이 사용할 수 있다.

 

<LoginDisplay.razor>

1
2
3
4
5
6
7
8
9
10
11
12
<AuthorizeView>
    <Authorized>
        <a href="Identity/Account/Manage">@context.User.FindFirst("RealName").Value</a>
        <form method="post" action="Identity/Account/LogOut">
            <button type="submit" class="nav-link btn btn-link">Log out</button>
        </form>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/ExternalLogin?provider=Google&returnUrl=/">Log in</a>
    </NotAuthorized>
</AuthorizeView>
 
cs

@context.User.FindFirst("RealName").Value

 

오늘은 여기까지!

 

#End.Code123 "코로나 조심하세요!"

+ Recent posts