ASP.NET Core Blazor Server에서 클레임 기반 승인 및 정책 기반 승인
이것은 순수한 로그인과 로그인하지 않는 것으로 디스플레이를 구분하고 볼륨 기반 승인을 이동합니다.오늘 이외에도 클레임과 정책에 기초한 비준을 시도해 보고 싶습니다.
그렇긴 하지만 며칠 전 보도된 내용까지 추적하면 곧 완성될 것이다.
클레임에 기초한 비준
다음 페이지는 정식 클레임 기반 승인 문서입니다.기본적으로 이걸 조립하는 형식입니다.
편입 전에 로그인 처리
Areas/MyLogin/Pages/Index.cshtml.cs
를 실시한 코드는 다음과 같다. 적당한 사용자 이름으로 클레임을 바꿨다.Index.cshtml.cs
using System.ComponentModel.DataAnnotations;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace AuthBlazorServerApp.Areas.MySignin.Pages;
public class IndexModel : PageModel
{
[BindProperty]
[Required]
public string? UserName { get; set; }
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid is false) return Page();
var userName = UserName!;
var principal = new ClaimsPrincipal(new ClaimsIdentity(
CreateClaims(userName),
CookieAuthenticationDefaults.AuthenticationScheme));
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
principal);
return Redirect("/");
}
private IEnumerable<Claim> CreateClaims(string userName)
{
yield return new Claim(ClaimTypes.Name, userName);
yield return new Claim(ClaimTypes.Role, "User");
if (userName == "Admin")
{
yield return new Claim(ClaimTypes.Role, "Administrator");
}
yield return userName switch
{
"Admin" => new Claim("EmployeeNumber", "0001"),
"Kazuki" => new Claim("EmployeeNumber", "0011"),
"Shinji" => new Claim("EmployeeNumber", "0111"),
"Kazuaki" => new Claim("EmployeeNumber", "1111"),
_ => new Claim("EmployeeNumber", "9999"),
};
}
}
그렇다면 클레임 인증을 바탕으로 다음과 같은 통제를 하고 싶습니다.Employee Number가 000100011명만 표시할 수 있도록 하기
FetchData.razor
.우선 엠플로이엔umber는 Program.cs
에서 000100011명만 통과할 수 있는 정책을 정의했다.Program.cs
builder.Services.AddAuthorization(options =>
{
// EmployeeNumber が 0001 か 0011 の人のみ通すポリシー
options.AddPolicy("EmployeeNumberIs0001Or0011", builder =>
{
builder.RequireClaim("EmployeeNumber", "0001", "0011");
});
});
위의 코드와 같이RequireClaim
특정 명칭의 고소와 수치가 완전히 일치하는 전략을 정의할 수 있다.이후 FetchData.razor
의 시작 등에 추가@attribute [Authorize(Policy = "EmployeeNumberIs0001Or0011")]
를 하면 페이지의 표시와 숨김 설정이 완성된다.FetchData.razor
@page "/fetchdata"
@attribute [Authorize(Policy = "EmployeeNumberIs0001Or0011")]
<PageTitle>Weather forecast</PageTitle>
@* 以下省略 *@
이렇게 하면 Admin이나 Kazuki로 들어갈 때를 제외하고는 FetchData.razor
페이지를 표시할 수 없습니다.실제 운행 후 아래와 같다.권한이 없는 사용자
FetchData.razor
App.razor
를 열면 NotAuthorized
시 로그인 페이지로 이동하도록 지정되어 있기 때문입니다.전략적 승인
그런 다음 정책 기반 승인을 받습니다.이것은 가장 자유로운 것이어서 무엇이든지 할 수 있다.
롤베이스→클레임 베이스→정책 기반 순으로 요건을 충족할 수 있는지 확인하는 형식으로 하는 게 좋을 것 같다.
다음 페이지에는 정책 기반 승인이 기재되어 있습니다.
전략의 실현 방법은 몇 가지 방법이 있지만 가장 큰 자유는 설치
IAuthorizationHandler
인터페이스나 계승AuthorizationHandler<T>
의 형식으로 이루어진다.그렇다면 엠플로이 넘버의 3위만 1이 되는 직원 번호를 허용하는 정책을 만들고 싶다.
실시
AuthorizationHandler
를 할 때 IAuthorizationRequirement
와 같은 구성원이 없는 표기 인터페이스를 설치한 클래스를 모델로 지정하여 실현하는 것이 좋다AuthorizationHandler<T>
.IAuthorizationRequirement
의 설치 클래스에서 승인 처리에서 사용할 매개 변수 등을 속성으로 정의할 수 있습니다.이것을 사용하면 비준 처리에 맞춤형 여지를 제공할 수 있다.이번 인정 논리는 3위가 1인 만큼 임의의 자릿수 값이 1이 되려면 IAuthorizationRequirement
의 실장류 속성에 이런 값을 설정할 수 있는 것을 추가하는 것이 좋다.일단 해봐.우선 Requirement를 만듭니다.이번에는 기호로만 사용했을 뿐 안은 비어 있었다.
TestRequirement.cs
using Microsoft.AspNetCore.Authorization;
namespace AuthBlazorServerApp.Auth;
public class TestRequirement : IAuthorizationRequirement
{
}
그리고 계승AuthorizationHandler<T>
하고 승인 논리를 HandleRequirementAsync
방법으로 쓴다.성공하면 context.Success(requirement);
라고 불러서 성공했다는 것을 나타낼 수 있다.부르지 않아도 다른 프로세서 호출Success
은 인정된다.Success
도 방법을 사용해서 절대로 실패할 수 있다.TestAuthHandler.cs
using Microsoft.AspNetCore.Authorization;
namespace AuthBlazorServerApp.Auth;
public class TestAuthHandler : AuthorizationHandler<TestRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TestRequirement requirement)
{
// EmployeeNumber の Claim があって
var employeeNumberClaim = context.User.Claims.FirstOrDefault(x => x.Type == "EmployeeNumber");
if (employeeNumberClaim is null) return Task.CompletedTask;
// 右から 3 桁目が 1 だったら OK (EmployeeNumber は 4 桁想定なので index = 1 が 3 桁目)
if (employeeNumberClaim.Value.Length == 4 && employeeNumberClaim.Value[1] == '1')
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
핸드프로세서 제작Fail
DI 컨테이너에 로그인합니다.Program.cs
// カスタムのハンドラー!
builder.Services.AddSingleton<IAuthorizationHandler, TestAuthHandler>(); // Scoped でも Transient でも可
그리고 Program.cs
등록 전략.방금 제작된AddAuthrization
지정을 통해TestRequirement
의TestAuthHandler
라고 할 수 있다.다음 코드는 Test라는 이름의 정책HandleRequirementAsync
입니다.Program.cs
builder.Services.AddAuthorization(options =>
{
// EmployeeNumber が 0001 か 0011 の人のみ通すポリシー
options.AddPolicy("EmployeeNumberIs0001Or0011", builder =>
{
builder.RequireClaim("EmployeeNumber", "0001", "0011");
});
// Test という名前のポリシーを登録
options.AddPolicy("Test", builder =>
{
// ここで IAuthorizationRequirement を実装したクラスを設定する。
builder.AddRequirements(new TestRequirement());
});
// デフォルトで認証されたユーザーが必要
options.FallbackPolicy = options.DefaultPolicy;
});
!정확히 말하면
TestAuthHandler
의 IAuthorizationHandler
방법은 매번 비준 시간에 호출된다.HandleAsync
에서 전달형 매개 변수AuthorizationHandler<T>
를 제외한 유형T
을 제외한 경우 필터IAuthorizationRequirement
가 이미 진행되었기 때문에 지정HandleRequirementAsync
이 설정되지 않은 정책에서 승인 처리를 건너뜁니다.이 점에 관해서는 글을 읽는 것보다 실제
Requirement
반의 실시 방식을 보는 것이 이해하기 쉽다./// <summary>
/// Base class for authorization handlers that need to be called for a specific requirement type.
/// </summary>
/// <typeparam name="TRequirement">The type of the requirement to handle.</typeparam>
public abstract class AuthorizationHandler<TRequirement> : IAuthorizationHandler
where TRequirement : IAuthorizationRequirement
{
/// <summary>
/// Makes a decision if authorization is allowed.
/// </summary>
/// <param name="context">The authorization context.</param>
public virtual async Task HandleAsync(AuthorizationHandlerContext context)
{
foreach (var req in context.Requirements.OfType<TRequirement>())
{
await HandleRequirementAsync(context, req).ConfigureAwait(false);
}
}
/// <summary>
/// Makes a decision if authorization is allowed based on a specific requirement.
/// </summary>
/// <param name="context">The authorization context.</param>
/// <param name="requirement">The requirement to evaluate.</param>
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement);
}
그러면 AuthorizationHandler<T>
속성의 정책 이름을 Test로 변경합니다.FetchData.razor
@page "/fetchdata"
@attribute [Authorize(Policy = "Test")]
<PageTitle>Weather forecast</PageTitle>
@* 以下略 *@
이렇게 되면 Shnji 또는 Kazaki를 통해서만 로그인할 수 있습니다FetchData.razor
.임의의 λ 공식을 통해 더욱 간단하게 검증할 수 있으며 방법은 위에서 보여준 문서를 참조하십시오.무의식적인 람다식으로 쉽게 완성할 수 있는 조건이라면 권저나 고소 기반을 활용할 수 있는 경우가 많다고 생각합니다.
정책 기초의 강대함
정책
Authorize
을 바탕으로 하는 실현 클래스는 구조기 주사기에서 모든 서비스를 받을 수 있도록 설정할 수 있다.예를 들어 하고 싶을 때마다 DB와 웹 API를 처리에서 호출합니다.무거우니까 안 하는 게 좋을 것 같아.할 때도 현금이 필요하거나 신경을 써야 하지만 뭐든지 할 수 있다는 게 강합니다.
노선 정보 쓰기 인정 논리 추가하고 싶어요.
FetchData.razor
의AuthorizationHandler
는App.razor
속성이 있는데 여기서 전달AuthorizeRouteView
하면Resource
에서 참조@routeData
할 수 있다.한번 해보세요.
AuthorizationHandler
의RouteData
줄을 아래와 같이 고쳤다.App.razor
<AuthorizeRouteView Resource="@routeData" RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
이렇게 하면 App.razor
의 방법AuthorizationRouteView
매개 변수AuthorizationHandler
의 속성context
에서 Resource
이 이미 지나갔음을 확인할 수 있다.그리고 하고 싶은 인정 논리에 맞춰 다양한 일을 했다.
전선으로 확인하고 싶어요.
지금까지 선언적으로 속성으로 정책적으로 허용된 사용자인지 확인했지만 코드 안에서도 확인하고 싶었습니다.
추측해 보자
RouteData
.테스트 정책의 사용자가 오면 모든 데이터의 Summary를 Warm으로 하자.사용자의 정보를 사용하고 싶어서 FetchData.razor
의 매개 변수로 수신WeatherForecastService
으로 변경했습니다.그리고 구조기로 수신ClaimsPrincipal
.IAuthorizationService
의 IAuthorizationService
방법을 사용하면 사용자가 정책에 만족하는지 확인할 수 있습니다.코드는 다음과 같습니다.
WeatherForecastService.cs
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
namespace AuthBlazorServerApp.Data;
public class WeatherForecastService
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly IAuthorizationService _authorizationService;
public WeatherForecastService(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
public async Task<WeatherForecast[]> GetForecastAsync(DateTime startDate, ClaimsPrincipal user)
{
// ユーザーが Test ポリシーを満たしているかどうか
var result = await _authorizationService.AuthorizeAsync(user, "Test");
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
// Test ポリシーを満たしているなら全データを Warm にする
Summary = result.Succeeded ? "Warm" : Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
}
}
호출자AuthorizeAsync
도 다음과 같이 사용자의 데이터를 취하여 FetchData.razor
에 건네준다.FetchData.razor
@* 上のマークアップ部分は省略 *@
@code {
[CascadingParameter]
private Task<AuthenticationState> AuthenticationState { get; set; } = null!;
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
var authState = await AuthenticationState;
forecasts = await ForecastService.GetForecastAsync(DateTime.Now, authState.User);
}
}
수행 후 다음과 같은 역할을 추측해 Test 정책을 충족시키는 사용자들은 Warm의 데이터를 자주 받는다.WeatherForecastService
의 IAuthorizationService
방법에도 수신AuthorizeAsync
의 과부하가 있다.이 옵션을 사용하면 정책 이름 대신 설치 범주AuthorizationPolicy
를 선택하여 확인할 수도 있습니다.var result = await _authorizationService.AuthorizeAsync(user, new AuthorizationPolicy(
new[] { new TestRequirement() }, // requirement
Enumerable.Empty<string>())); // aithenticationSchemas
총결산
그래서 ASP를 둘로 나눠 샀어요.NET Core Blazer Server에서 로그인 기능을 설치하는 방법과 이를 승인하는 방법을 보았습니다.
제 로그인 기능이지만 Http Context의 User에 Claims Principal을 설정하면 이후에 다양한 끼워넣는 편리한 기능을 사용할 수 있습니다.
IdP를 잘 사용하고 싶을 때 로그인 화면이 필요 없으면 더 편할 거예요.
이 글을 쓰면서 쓴 코드는 아래 창고에 있습니다.
Reference
이 문제에 관하여(ASP.NET Core Blazor Server에서 클레임 기반 승인 및 정책 기반 승인), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/okazuki/articles/add-policybaseauth-and-claimbaseauth텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)