OAuth 인증의 이해 5


이 시리즈의 모든 글 보기 : oauth


이전 글의 마지막에 API가 보호되지 않고 있다고 언급했습니다.

그 증거로, RP, AC 두 앱을 실행시킨 후, AC의 로그인 버튼을 누르지 않은 채, 새로운 탭을 열어 RP/weatherforecast 에 접근하면, 아래와 같이 날씨 데이터를 받을 수 있습니다.

RP/weatherforecast 는 아무나 접근할 수 있는 것이죠.

API 보호

이제 API(RP)에 구글 인증 결과를 바탕으로 엔드 포인트를 보호하도록 하겠습니다.

아시다시피, Asp.Net Core에서 엔드 포인트를 보호하기 위해서는, 인증/인가를 미들웨어를 사용해야 합니다. 이들에 대해 대해 잠깐 알아 보겠습니다.

인증 미들웨어 (Authentication middleware)

인증 미들웨어는 요청에 포함된 인증 수단을 바탕으로 HttpContext.User 를 할당하는 역할(만)을 수행합니다.

이전 글에서도 설명했지만, 인증은 로그인과 다릅니다.
로그인은 인증 수단을 발급(응답)하는 행위이고, 인증은 발급된 인증 수단을 검사하는 행위입니다.

인증 수단 검사는 모든 요청에 대해 실행됩니다.

검사 결과가 성공적이든 아니든, HttpContext.User를 할당한 후, 그 다음 미들웨어를 호출합니다. 즉 응답하지 않습니다.

인증 미들웨어의 행위를 한 마디로 정의하면, Authenticate 입니다.

인가 미들웨어 (Authorization middleware)

인증 미들웨어의 결과가 응답에 영향을 주기 위해서는 인가 미들웨어가 있어야 합니다.

인가 미들웨어는 어떤 엔드 포인트를, 누구에게 허락할 것 인지에 대해 알고 있습니다. (우리가 사전에 설정하니까요). 이때, "누구"는 인증 미들웨어가 설정한 HttpContext.User 를 가리킵니다.

인증 미들웨어와 달리, 인가 미들웨어는 기본적으로 아래의 응답을 보낼 수 있습니다.

  • Challenge (401 또는 302)
    사용자가 확인이 안된 경우.
  • Forbid (403)
    사용자는 확인이 되었는데, 접근 권한이 없는 경우.

사용자도 확인 되었고, 접근 권한도 확인된 경우, 인가 미들웨어는 응답을 하지 않습니다.
그 결과로 엔드 포인트가 호출되어 응답을 수행합니다.

IAuthenticationService

종합해 보면, 엔드 포인트를 보호하기 위한 주요 행위는 아래와 같습니다.

  • Authenticate
  • Forbid
  • Challenge

여기에, 인증 수단을 자체적으로 발급할 경우, 인증 수단 생성/폐기도 포함되겠죠.

  • Signout
  • Signin

Asp.Net Core 에서는 이러한 기능을 하나의 인터페이스로 정의했고, 인증/인가 미들웨어는 이 객체에 의존하도록 설계되었습니다.

IAuthenticationService Interface (Microsoft.AspNetCore.Authentication) | Microsoft Learn

이름이 IAuthenticationService 이지만, 이 객체는 인증/인가, 그리고 로그인까지 전부 관여합니다.

AuthenticationScheme

여러 개의 인증 방식을 적용할 경우, 여러 개의 IAuthenticationService 를 구현하고, 아래와 같이 의존성 등록을 해야 할 것 같지만,

builder.Services.AddSingleton<IAuthenicationService, CookieAuthService>();
builder.Services.AddSingleton<IAuthenicationService, TokenAuthService>();

아래와 같이, 하나의 IAuthenticationService에 여러 개의 인증 스킴을 등록하는 구조로 되어 있습니다.

builder.Service.AddAuthentication()
   .AddScheme("CookieScheme", // ... )
   .AddScheme("TokenScheme", // ... )

이때, IAuthenticationService 의 구현 객체는 서비스 컨테이너에 등록되어 있지만, 우리는 그 실체를 볼 수는 없습니다.

이렇게 하나의 인증 서비스가 여러 개의 인증 스킴을 사용하도록 만든 이유는, 과거(~7.0)에는 서비스 컨테이너에 Keyed Resolve 기능이 없었기 때문인 것 같습니다.

builder.Services.AddSingleton<IAuthenicationService, CookieAuthService>(“Cookie”);
builder.Services.AddSingleton<IAuthenicationService, TokenAuthService>(“Token”);

Keyed Resolve 기능은 8.0 부터 도입되었기 때문에, 조만간 복수의 스킴을 사용하는 방식에서 복수의 IAuthenticationService 를 사용하는 방식으로 변경될 가능성도 있을 것 같습니다.

또한, Asp.Net Core 는 기본적으로 쿠키 인증 스킴과, 토큰(JWT 아님) 인증 스킴을 구현해서 제공하고, 이들을 등록하는 확장 메서드도 제공하는데, 이 확장 메서드를 이용해서, 인증 서비스와 인증 스킴을 등록하는 것이 일반적입니다.

builder.Services.AddAuthentication("Cookie") // 인가 미들웨어에 스킴을 지정하지 않으면 "Cookie" 스킴을 사용해라.
   .AddCookie("Cooke")
   .AddToken("Token");

사실 이 두 확장 메서드 내부에서 AddScheme 이 호출됩니다.

커스텀 인증 스킴

그런데, 이 두 확장 메서드는 편리하기도 하지만, 구현에 편향성이 있어 우리 맘에 쏙 들지 않을 때가 있습니다.

예를 들어, 쿠키에 너무 많은 데이터를 넣어 쿠키 값이 긴 편이고, 토큰도 전용 토큰이라, JWT 와 같이 범용적 사용이 어렵습니다.

더 큰 문제는 인증 스킴들의 행위를 변경하는 것에도 제한이 있다는 점입니다.

그래서, 이 글에서는 AddScheme 을 통해 새로운 스킴을 정의할 것인데, 세션 쿠키를 바탕으로 인증/인가를 수행하도록 만들 것입니다.

IAuthenicationHandler

인증 스킴을 정의할 때 우리가 제공해야 하는 속성은 아래와 같습니다.

  • 인증 스킴 이름
    인증 스킴의 식별자로, 인가 미들웨어 또는 인가 정책(Authorization Policy)에서 사용됩니다.

  • IAuthenicationHandler
    실제 인증 구현을 담고 있는 객체

이름이야 마음 대로 지으면 되고, 우리에게 중요한 것은 IAuthenicationHandler 객체입니다.

이름이 IAuthenicationHandler 이지만, 인증/인가 모두에 관여함을 알 수 있습니다.

보시다 시피, 인증 핸들러(IAuthenicationHandler)는 인증/인가에 관계된 행위를 가지고 있는데, 이들은 인증 서비스(IAuthenticationService) 객체에 의해 호출됩니다.

우리가 커스텀 인증 스킴을 정의할 때, 적어야 하는 코드는 이 인터페이스를 구현하는 것이 거의 전부입니다.

“그런데, 말입니다.”

AuthenticationHandler

Asp.Net Core 는 IAuthenicationHandler 의 구현 편의를 위해 기본적인 구현을 해 놓은 AuthenticationHandler 도 제공합니다.

상위 객체인 IAuthenicationHandler 를 구현할 지, 그 인터페이스의 상당 부분을 구현해 놓은 AuthenticationHandler 클래스를 파생할 지는 선택의 문제입니다.

이 선택을 위해, AuthenticationHandler 의 구현을 짤막하게 짚어 보자면,

  • AuthenticateAsync 는 abstract 라서, 우리가 구현해야 합니다.
  • ChallengeAsync 는 401 을 응답합니다.
  • ForbidAsync 는 403 을 응답합니다.

구현 방식이 API 앱에 적당해 보이기 때문에, AuthenticationHandler 를 파생하여 손 가락 고생을 덜어 봅니다.

기본 설명은 여기까지이고, 마침내 실제 구현에 들어 갑니다.

AuthenticationHandler 구현

RP 프로젝트에 아래 두 클래스를 추가합니다.

namespace PUCB.Backend;

internal class SessionTokenAuthSchemeHandler
    : AuthenticationHandler<SessionTokenAuthSchemeOptions>
{
    private const string USERINFO_SESSION_KEY = "userInfo";
    public SessionTokenAuthSchemeHandler(
        IOptionsMonitor<SessionTokenAuthSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder) : base(options, logger, encoder)
    {
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        await Task.CompletedTask;

        var userInfoJson = Context.Session.GetString(USERINFO_SESSION_KEY);

        if (string.IsNullOrWhiteSpace(userInfoJson) ||
            JsonSerializer.Deserialize<UserInfo>(userInfoJson) is not UserInfo userInfo ||
            userInfo.IsValid() is false)
            return AuthenticateResult.Fail("Invalid request");

        var claims = new[] {
            new Claim(ClaimTypes.Name, userInfo.Name),
            new Claim(ClaimTypes.Email, userInfo.Email)
        };

        var identity = new ClaimsIdentity(claims, "Backend Session Cookie");
        var principal = new ClaimsPrincipal(identity);

        var ticket = new AuthenticationTicket(principal, this.Scheme.Name);
        return AuthenticateResult.Success(ticket);
    }
}
  • HandleAuthenticateAsync() 에서, 세션이 유효하지 않거나, 세션 데이터가 잘못된 경우, 실패한 인증 결과를, 성공적인 경우, 인증 티켓을 포함하는 성공한 인증 결과를 반환합니다.

using Microsoft.AspNetCore.Authentication;

namespace PUCB.Backend;

internal class SessionTokenAuthSchemeOptions
    : AuthenticationSchemeOptions
{
}
  • 스킴 옵션은 주로 다른 스킴과의 협업을 설정할 때 사용합니다.
    우리는 다른 스킴에 의존하지 않기 때문에, 빈 파생으로 정의했습니다.

빈 파생 대신, AuthenticationSchemeOptions 를 직접 사용해도 됩니다.


그리고, RP의 Program.cs에 아래와 같이 인증 서비스(가 의존할), 인증 스킴(이 의존할), 인증 스킴 옵션과 인증 핸들러를 서비스 등록합니다.

builder.Services.AddAuthentication()
    .AddScheme<SessionTokenAuthSchemeOptions, SessionTokenAuthSchemeHandler>(
        "SessionCookie", 
        options => { }
    );
builder.Services.AddAuthorization();
  • 위 객체들은 내부에서 Singleton 으로 등록됩니다.

  • 추가한 스킴의 이름은 "SessionCookie"으로 설정했습니다.

8.0 에서는 위의 설정으로, “SessionCookie” 스킴이 기본 인증 스킴으로 자동으로 설정됩니다.
그러나, 그 이하 버전에서는 기본 스킴을 명시적으로 지정해야 합니다.
기본 인증 스킴은 인가 요구 표시에 스킴을 지정하지 않으면 자동으로 선택되는 스킴입니다.
아래에서 다시 언급하겠습니다.

  • 빈 스킴 옵션이기 때문에, 옵션을 설정하지 않았습니다.

인증/인가 미들웨어를 추가합니다.

// ...

// 미들웨어 순서 중요
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
  • 인증 미들웨어는 세션 쿠키에 기반하기 때문에, 반드시 세션 미들웨어 뒤에 와야 합니다.
  • 인가 미들웨어는 인증 미들웨어의 결과를 사용하기 때문에, 인증 미들웨어 뒤에 와야 합니다.

테스트

세션 쿠키를 기반한 인증/인가를 위한 인프라를 모두 설정했습니다.

이를 테스트하기 위해, /userinfo 엔드 포인트를 아래와 같이 변경합니다.

app.MapGet("/userinfo", (ClaimsPrincipal user) =>
{
    //var userInfoJson = httpContext.Session.GetString(USERINFO_SESSION_KEY);

    //if (string.IsNullOrWhiteSpace(userInfoJson) ||
    //    JsonSerializer.Deserialize<UserInfo>(userInfoJson) is not UserInfo userInfo)
    //    return Results.Unauthorized();
    var userInfo = new UserInfo(    
    user.FindFirstValue(ClaimTypes.Email) ?? "",
    user.FindFirstValue(ClaimTypes.Name) ?? "");
    return Results.Ok(userInfo);
});
  • 이전 코드는 엔드포인트가 직접 인가를 수행하는 구조였습니다.
    return Results.Unauthorized();

  • 새로운 코드는, 엔드 포인트는 본연의 역할인, UserInfo 를 응답하는 책임에만 집중합니다.
    왜냐하면, 인가는 인가 미들웨어가 책임지고 있기 때문입니다. (Challenge, Forbid)

엔드 포인트의 책임과 인가의 책임이 명확히 분리되는 것이, 인증/인가 미들웨어 도입의 효과입니다.


인증 미들웨어 테스트

두 앱을 실행한 다음, 로그인을 하지 말고, 새 탭을 열어 RP/userinfo 에 주소를 입력합니다.
그러면, 아래와 같은 Json 객체를 응답합니다.

{
    "email": "",
    "name": ""
}

이제 UI 앱 탭으로 돌아가 로그인을 한 후, 다시 열려 있는 새탭으로 돌아와 refresh 를 누르면 사용자 정보를 응답 받을 수 있습니다.

{
    "email": "XXXX",
    "name": "XXX@gmail.com"
}

이 테스트를 통해 인증 미들웨어는 모든 요청에 대해 동작한다는 점을 알 수 있습니다.

인가 요구

그런데, 우리는 인증/인가를 위한 인프라를 제대로 설정했지만, 401이나, 403을 받지 못하고 있습니다.

이는 인증 미들웨어는 열심히 일을 하고 있는 반면, 인가 미들웨어는 그렇지 않음을 의미합니다.
인가 미들웨어는 보호할 대상을 지정하지 않으면 일을 하지 않습니다.

/weatherforecast/userinfo 맵핑 메서드 마지막에 RequireAuthorization()을 붙여 인가 미들웨어에게 일거리를 줘 봅니다.

// ...
app.MapGet("/weatherforecast", () =>
{
    //...
    return forecast;
}).RequireAuthorization();

//...
app.MapGet("/userinfo", (ClaimsPrincipal user) =>
{
    //...
    return Results.Ok(userInfo);
}).RequireAuthorization();
//...
  • RequireAuthorization() 메서드의 파라 미터로 인증 스킴이나 인증 정책을 지정해야 합니다.
    만약 지정하지 않으면, 기본 인증 스킴이 적용됩니다.

두 앱을 다시 실행시킨 후, 로그인을 누르지 말고, 새로운 탭을 열어, userinfo 나 weatherforecast 엔드 포인트에 접근해 보면, 401 응답을 받을 것입니다.

그 다음, 앱의 탭으로 돌아가서, 이번에는 로그인을 하고, 다시 엔드 포인트 탭으로 돌아 와, 새로 고침을 하면, 올바른 데이터를 얻을 수 있습니다.

이는 인가 미들웨어가 제대로 일하고 있음 - 지정된 엔드 포인트를 보호하고 있음을 의미합니다.

세션 쿠키의 특징

이 상태에서, 브라우저의 개발 도구를 연 후, [응용 프로그램(Applciation)] 탭을 선택하고, 좌측 메뉴에서 쿠키 항목을 보시면, 세션 쿠키가 보일 것입니다.

Asp.Net Core 가 기본으로 제공하는 쿠키 스킴을 사용했을 때보다, 쿠키의 길이가 짧다는 점을 알 수 있습니다. 기본 쿠키 스킴은 사용자 정보를 쿠키에 저장하지만, 세션 쿠키 스킴에서는 세션 ID 만 쿠키에 저장되기 때문입니다.

Redirect 기반 Challenge 주의

Challenge 는 사용자가 로그인 하지 않고 보호된 엔드 포인트를 접근하는 시나리오에서 발동합니다. 예를 들면, 세션 쿠키 생성 과정 없이, RP/weatherforecast에 바로 fetch를 보낸 경우입니다.

우리가 구현은 인증 핸들러의 ChallengeAsync는 401을 응답하기 때문에, 위 시나리오에서 401 응답 받습니다.

이 메서드가 401 대신, Redirect 기반의 응답(3xx)을 해서, 구글 인증을 거치도록 만들 수 있습니다.

예를 들면 아래와 같이 RP 프로젝트의 SessionTokenAuthSchemeHandler에 아래의 오버라이드를 추가하는 것이죠.

internal class SessionTokenAuthSchemeHandler
{
//...
    protected override Task HandleChallengeAsync(AuthenticationProperties properties)
    {
        Response.Redirect("/grant/google");
        return Task.CompletedTask;
    }
}

RP가 이렇게 응답하면, AC(의 HttpClient) 는 RP/grant/google 로 Follow 하고, 다시 구글 승인 엔드포인트로 Follow 합니다.

Redirect 응답의 Location 에 다시 요청을 보내는 행위를 Follow 라고 합니다.

그러나, 이러한 구현은 우리 시스템에 적용할 수 없습니다.

문제 1 : 승인 서버 CORS 정책

적용할 수 없는 첫 번째 이유는 승인 서버에 대한 Follow는 fetch 이기 때문입니다.

승인 서버는 이 fetch 를 Cross Site 요청으로 보고 응답 하지 않습니다.
실제로 실행해 보면 CORS 관련 예외를 볼 수 있습니다.

이 CORS 예외를 해결하려면, AC가 fetch 요청에 대해 Redirect 응답을 받은 경우, 직접 Follow 하지 않고, 브라우저를 Follow 하도록, 다시 말하면 Navigate 하도록 만들면 됩니다. (AC의 로그인 버튼이 하는 것처럼)

현재 AC가 보내는 fetch는 HttpClient 가 담당합니다.
HttpClient 는 기본적으로 Redirect 를 직접 Follow 하게 설정되어 있는데, 이를 바꿀 수 있습니다.
아래와 같이 말이죠.

// AC 프로젝트의 Program.cs

builder.Services
    .AddTransient<CookieHandler>()
    .AddScoped(sp => sp
        .GetRequiredService<IHttpClientFactory>()
        .CreateClient("API"))
    .AddHttpClient("API", (sp, client) =>
    {
        client.BaseAddress = new(rp.Host);
    })
    .ConfigurePrimaryHttpMessageHandler(_ =>
        new HttpClientHandler
        {
            AllowAutoRedirect = false,
        }
    )
    .AddHttpMessageHandler<CookieHandler>()
    .AddHttpMessageHandler<NavigateOnChallengeHandler>()
    ;

ConfigurePrimaryHttpMessageHandler 는 HttpClient 의 기저 메시지 핸들러(HttpClientHandler)를 설정할 수 있게 해줍니다. 참고로, HttpClient 의 내부는 메시지 핸들러 파이프 라인 구조로 되어 있습니다. (Asp.Net Core 의 미들웨어 파이프 라인과 같은 개념입니다)

image

아래 코드는, 위 그림에서 HttpCientHandler 가 자동으로 Follow 하지 않게 설정한 것입니다.

.ConfigurePrimaryHttpMessageHandler(_ =>
        new HttpClientHandler
        {
            AllowAutoRedirect = false,
        }
    )

그리고, 두 개의 커스텀 핸들러를 등록했는데, 하나는 브라우저의 쿠키를 요청에 실을 수 있게 한 것이고(지난 글에서 구현), 다른 하나는 Redirect 응답을 받았을 때 처리를 담당합니다.

using Microsoft.AspNetCore.Components;

namespace PUCB.Wasm;

internal class NavigateOnChallengeHandler(NavigationManager navMan) : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if (response.StatusCode == System.Net.HttpStatusCode.Redirect &&
            response.Headers.Location?.ToString() is string location &&
            location.Contains("/grant"))
        {
            navMan.NavigateTo(location, true);
        }
        
        return response;
    }
}

문제 2 : 브라우저의 wasm 정책

그러나, 현재 AC 앱은 wasm 기반이고, 내부에서 사용하는 HttpClient 는 fetch API(자바스크립트 fetch 함수) 기반합니다.

브라우저는, wasm 에서 실행 시킨 fetch 가 Redirect 를 (Follow 하지 않고) 직접 처리하는 것을 금지 하는 보안 정책을 가지고 있습니다.

그 결과로 HttpClient 가 Redirect 를 Follow 하지 않도록 설정하면, Redirect 응답에 대한 정보를 획득할 수 없게 됩니다. 즉, 아래 코드에서,

        if (response.StatusCode == System.Net.HttpStatusCode.Redirect &&
            response.Headers.Location?.ToString() is string location &&
            location.Contains("/grant"))

response.StatusCode 에는 0이, response.Headers.Location에는 null 이 설정됩니다.

위 정보 없이는 Redirect 를 처리하는 것이 불가능합니다.

이 경우, 우리가 선택할 수 있는 방법은 Challenge 가 401 을 응답하도록 놔두고, AC가 401 응답을 받았을 때, 브라우저를 세션 생성 엔드 포인트로 Navigate 하도록 만들면 됩니다.

이를 담당할 http 메세지 핸들러는 아래와 같이 정의할 수 있습니다.

using Microsoft.AspNetCore.Components;

namespace PUCB.Wasm;

internal class NavigateOnUnauthorizedHandler(NavigationManager navMan) : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
        {
            navMan.NavigateTo("login/google", true);
        }

        return response;
    }
}

추가 조치로 Login.razor 를 만들어야겠죠.

그런데, 이렇게 복잡한 구현을 하는 것도 방법이지만, 아래와 같이 AC 에서, 401 을 받을 만한 요청을 보내는 것을 차단하는 방법도 있습니다.

API 보호에 대한 AC의 구성

그 방법은 AC 의 NavMenu.razor 에서 weather 메뉴가 비 로그인 상태에서는 보이지 않게 만드는 것입니다.

<div class="@NavMenuCssClass nav-scrollable" @onclick="ToggleNavMenu">
    <nav class="flex-column">
       ...
        <AuthorizeView>
            <Authorized>
                <div class="nav-item px-3">
                    <NavLink class="nav-link" href="weather">
                        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
                    </NavLink>
                </div>
            </Authorized>
        </AuthorizeView>

    </nav>
</div>

이러한 조치로 사용자는 로그인 하지 않고서는 /weatherforecast/ 에 요청을 보내는 메뉴를 선택할 수 없습니다. AC 앱이 아닌 다른(Postman 과 같은) 클라이언트 앱을 사용해서 이 주소로 요청을 보내도 401을 받을 뿐입니다.

추가적으로 Weather.razor 도 뷰 영역에 <AuthorizeView> 요소를 쓰지 않고, 코드 영역만 로그인 상황을 고려하도록 간편하게 대응할 수도 있습니다.

...
<p>fetching data from Backend.</p>

@if (forecasts == null)
{
  ...


@code {

    [CascadingParameter]
    private Task<AuthenticationState> AuthState { get; set; } = null!;
    private WeatherForecast[]? forecasts;

    protected override async Task OnInitializedAsync()
    {
        // if ((await AuthState).User.Identity?.IsAuthenticated == false) // <= 이건 안됨 주의
        if ((await AuthState).User.Identity?.IsAuthenticated != true)
            return;

        forecasts = await Http.GetFromJsonAsync<WeatherForecast[]?>("/weatherforecast");
    }

범용성

블레이저 와즘앱을 위와 같이 구성하면, 그 앱은 큰 코드 수정 없이 다른 블레이저 하이브리드 앱에 사용할 수 있습니다.

이와 관련해서는 아래의 글을 참고하세요.

마치며

지금까지 OIDC 인증 클라이언트를 직접 구현하고, 이를 우리 시스템에 적용하는 방법과 주의점에 대해 알아 보았습니다.

꽤 긴 글이었고, 여기 까지 읽으신 분들은 수고 많으셨습니다.

시리즈 군데 군데 보여드린 것처럼, 실제로 이를 적용하는 것은 상당히 높은 주의를 요구합니다.
그래서, 보통은 외부 라이브러리를 의존하는 것이 추천됩니다.

이 글은 그 외부 라이브러리 문서를 이해하는 초석이 되었으면 합니다.

원래는 외부 라이브러리 하나를 선택해서 사용하는 방법까지 다루려고 했으나, 그 부분은 그 라이브러리의 문서를 직접 참조하는 것이 더 좋을 것 같다는 판단으로 소개하는 것을 마지막으로, 이 시리즈를 마치도록 하겠습니다.

OpenIdDict

현재, 닷넷에서, OAUTH/OIDC 인증 구현 시에 추천되는 라이브러리는 OpenIddict 입니다.

이 라이브러리는 오픈 소스이고, OP 서버와 OP 클라이언트를 분리해 놓았습니다.
특히, OP 클라이언트는 OpenIddict 서버 전용이 아니라, 외부 OP에도 사용할 수 있도록 범용으로 구현해 놓았습니다.

오픈 소스 답게, 잘 알려진 유명한 OP를 위한 클라이언트 구현도 대부분 준비 되어 있습니다.


만약 OP 서버를 작성하고자 한다면, 아래 링크로부터 시작하시면 됩니다.

  • your own server 는 직접 운영하게 될 OP 서버입니다. Asp.net Core 에 잘 통합되어 있습니다.

OP 클라이언트를 작성하는 경우, 아래 링크로부터 시작하시면 됩니다.

  • “remote server” 는 (구글 같은) 외부 OP 를 가리킵니다.
  • BFF 패턴에 적용하려면, OP 클라이언트로 Asp.Net Core Web Api 가 되어야 하고, 승인 코드 흐름을 선택해야 합니다.

5 Likes

너무 흥미롭게 잘 보고 있었습니다. 감사합니다

써드파티 라이브러리 언급나온 김에

최근에는 KeyClock에 관심이 가더라구요.

Apache 2.0 라이센스에, Hangfire 처럼 UI도 기본 제공되는게

아주 괜찮아 보였습니다.

1 Like