다음을 통해 공유


ASP.NET Core에서 OpenID Connect Web(UI) 인증 구성

작성자: Damien Bowden

샘플 코드 보기 또는 다운로드

이 문서에서는 다음 영역에 대해 설명합니다.

  • OpenID Connect 기밀 대화형 클라이언트란?
  • ASP.NET Core에서 OpenID Connect 클라이언트 만들기
  • 코드 조각이 있는 OpenID Connect 클라이언트의 예
  • 타사 OpenID Connect 공급자 클라이언트 사용
  • BFF(프런트 엔드) 보안 아키텍처용 백 엔드
  • 고급 기능, 표준, OpenID Connect 클라이언트 확장

OpenID Connect 기밀 대화형 클라이언트란?

OpenID Connect 를 사용하여 ASP.NET Core 애플리케이션에서 인증을 구현할 수 있습니다. 권장되는 방법은 코드 흐름을 사용하여 OpenID Connect 기밀 클라이언트를 사용하는 것입니다. 이 구현에는 OAuth PKCE(공용 클라이언트) 의 코드 교환에 대한 증명 키를 사용하는 것이 좋습니다. 애플리케이션 클라이언트와 애플리케이션의 사용자 모두 기밀 흐름에서 인증됩니다. 애플리케이션 클라이언트는 클라이언트 암호 또는 클라이언트 어설션을 사용하여 인증합니다.

공용 OpenID Connect/OAuth 클라이언트는 웹 애플리케이션에 더 이상 권장되지 않습니다.

기본 흐름은 다음 다이어그램과 같이 작동합니다.

PKCE를 사용하는 OIDC 코드 흐름 기밀 클라이언트

OpenID Connect는 다양한 변형으로 제공되며 모든 서버 구현에는 약간 다른 매개 변수와 요구 사항이 있습니다. 일부 서버는 사용자 정보 엔드포인트를 지원하지 않으며 일부는 여전히 PKCE를 지원하지 않으며 다른 서버는 토큰 요청에 특수 매개 변수가 필요합니다. 클라이언트 어설션은 클라이언트 비밀 대신 사용할 수 있습니다. 다운스트림 API에 대한 FAPI, CIBA 또는 DPoP와 같은 OpenID Connect Core 위에 보안을 추가하는 새로운 표준도 있습니다.

참고 항목

OpenID Connect 서버에서 지원하는 경우 .NET 9 에서 OAuth 2.0 PAR(푸시된 권한 부여 요청) RFC 9126 이 기본값으로 사용됩니다. 위와 같이 2단계 흐름이 아닌 3단계 흐름입니다. (사용자 정보 요청은 선택적 단계입니다.)

Pages를 사용하여 Razor Open ID Connect 코드 흐름 클라이언트 만들기

다음 섹션에서는 빈 ASP.NET Core Razor 페이지 프로젝트에서 OpenID Connect 클라이언트를 구현하는 방법을 보여줍니다. UI 통합만 다른 ASP.NET Core 웹 프로젝트에 동일한 논리를 적용할 수 있습니다.

OpenID Connect 지원 추가

Microsoft.AspNetCore.Authentication.OpenIdConnect Nuget 패키지를 ASP.NET Core 프로젝트에 추가합니다.

OpenID Connect 클라이언트 설정

작성기를 사용하여 웹 애플리케이션에 인증을 추가합니다. Program.cs 파일의 서비스입니다. 구성은 OpenID Connect 서버에 따라 달라집니다. 각 OpenID Connect 서버에는 설정에 약간의 차이가 필요합니다.

OpenID Connect 처리기는 챌린지 및 로그아웃에 사용됩니다. 웹 cookie 애플리케이션에서 세션을 처리하는 데 사용됩니다. 인증에 대한 기본 체계는 필요에 따라 지정할 수 있습니다.

자세한 내용은 ASP.NET Core [authentication-handler](xref: security/authentication/index?view=aspnetcore-8.0#authentication-handler)를 참조하세요.

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");

    options.Authority = oidcConfig["Authority"];
    options.ClientId = oidcConfig["ClientId"];
    options.ClientSecret = oidcConfig["ClientSecret"];

    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.ResponseType = OpenIdConnectResponseType.Code;

    options.SaveTokens = true;
    options.GetClaimsFromUserInfoEndpoint = true;

    options.MapInboundClaims = false;
    options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
    options.TokenValidationParameters.RoleClaimType = "roles";
});

다양한 OpenID Connect 옵션에 대한 자세한 내용은 OIDC(OpenID Connect)를 사용하여 ASP.NET Core Blazor Web App 보안을 참조하세요.

ASP.NET Core에서 다양한 클레임 매핑 가능성에 대한 매핑, 사용자 지정 및 변환을 참조하세요.

참고 항목

다음 네임스페이스가 필요합니다.

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;

구성 속성 설정

애플리케이션 구성 속성에 OpenID Connect 클라이언트 설정을 추가합니다. 설정은 OpenID Connect 서버의 클라이언트 구성과 일치해야 합니다. 실수로 체크 인될 수 있는 애플리케이션 설정에는 비밀을 유지하지 않아야 합니다. 비밀은 프로덕션 환경의 Azure Key Vault와 같은 안전한 위치 또는 개발 환경의 사용자 비밀에 저장되어야 합니다. 앱 비밀을 참조 하세요.

"OpenIDConnectSettings": {
  // OpenID Connect URL. (The base URL for the /.well-known/openid-configuration)
  "Authority": "<Authority>",
  // client ID from the OpenID Connect server
  "ClientId": "<Client ID>",
  //"ClientSecret": "--stored-in-user-secrets-or-key-vault--"
},

프로그램 클래스에서 ASP.NET Core 파이프라인 메서드를 업데이트합니다.

UseAuthorization 메서드 앞에 UseRouting을 구현해야 합니다.

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();
app.UseAuthentication();
// Authorization is applied for middleware after the UseAuthorization method
app.UseAuthorization();
app.MapRazorPages();

강제 권한 부여

보호된 razor 페이지에 Authorize 특성을 추가합니다(예: Index.cshtml.cs 파일).

[Authorize]

더 나은 방법은 전체 애플리케이션에 권한을 부여하고 안전하지 않은 페이지를 옵트아웃하도록 강제하는 것입니다.

var requireAuthPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();

builder.Services.AddAuthorizationBuilder()
    .SetFallbackPolicy(requireAuthPolicy);

프로젝트에 새 Logout.cshtml 및 SignedOut.cshtml Razor 페이지 추가

세션과 OpenID Connect 세션을 모두 cookie 로그아웃하려면 로그아웃이 필요합니다. 로그아웃하려면 전체 애플리케이션이 OpenID Connect 서버로 리디렉션되어야 합니다. 로그아웃에 성공하면 애플리케이션이 RedirectUri 경로를 엽니다.

기본 로그아웃 페이지를 구현하고 다음을 사용하여 로그아웃 razor 페이지 코드를 변경합니다.

[Authorize]
public class LogoutModel : PageModel
{
    public IActionResult OnGetAsync()
    {
        return SignOut(new AuthenticationProperties
        {
            RedirectUri = "/SignedOut"
        },
        // Clear auth cookie
        CookieAuthenticationDefaults.AuthenticationScheme,
        // Redirect to OIDC provider signout endpoint
        OpenIdConnectDefaults.AuthenticationScheme);
    }
}

SignedOut.cshtml AllowAnonymous 특성이 필요합니다.

[AllowAnonymous]
public class SignedOutModel : PageModel
{
    public void OnGet()
    {
    }
}

로그인 페이지 구현

필요한 AuthProperties를 사용하여 ChallengeAsync를 직접 호출하도록 로그인 Razor 페이지를 구현할 수도 있습니다. 전체 웹 애플리케이션에 인증이 필요하고 기본 챌린지를 사용하는 경우에는 이 작업이 필요하지 않습니다.

login.cshtml AllowAnonymous 특성이 필요합니다.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPageOidc.Pages;

[AllowAnonymous]
public class LoginModel : PageModel
{
    [BindProperty(SupportsGet = true)]
    public string? ReturnUrl { get; set; }

    public async Task OnGetAsync()
    {
        var properties = GetAuthProperties(ReturnUrl);
        await HttpContext.ChallengeAsync(properties);
    }

    private static AuthenticationProperties GetAuthProperties(string? returnUrl)
    {
        const string pathBase = "/";

        // Prevent open redirects.
        if (string.IsNullOrEmpty(returnUrl))
        {
            returnUrl = pathBase;
        }
        else if (!Uri.IsWellFormedUriString(returnUrl, UriKind.Relative))
        {
            returnUrl = new Uri(returnUrl, UriKind.Absolute).PathAndQuery;
        }
        else if (returnUrl[0] != '/')
        {
            returnUrl = $"{pathBase}{returnUrl}";
        }

        return new AuthenticationProperties { RedirectUri = returnUrl };
    }
}

사용자에 대한 로그인, 로그아웃 단추를 추가합니다.

@if (Context.User.Identity!.IsAuthenticated)
{
	<li class="nav-item">
		<a class="nav-link text-dark" asp-area="" asp-page="/Logout">Logout</a>
	</li>

	<span class="nav-link text-dark">Hi @Context.User.Identity.Name</span>
}
else
{
	<li class="nav-item">
		<a class="nav-link text-dark" asp-area="" asp-page="/Index">Login</a>
	</li>
}

코드 조각이 있는 예제

사용자 정보 엔드포인트 사용 예제

OpenID Connect 옵션은 클레임을 매핑하거나, 처리기를 구현하거나, 나중에 사용할 수 있도록 세션에 토큰을 저장하는 데 사용할 수 있습니다.

범위 옵션은 OpenID Connect 서버에 정보로 전송되는 다른 클레임 또는 새로 고침 토큰을 요청하는 데 사용할 수 있습니다. offline_access 요청하면 애플리케이션 사용자를 다시 인증하지 않고 세션을 새로 고치는 데 사용할 수 있는 참조 토큰을 반환하도록 서버에 요청합니다.

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");
    options.Authority = oidcConfig["IdentityProviderUrl"];
    options.ClientSecret = oidcConfig["ClientSecret"];
    options.ClientId = oidcConfig["Audience"];
    options.ResponseType = OpenIdConnectResponseType.Code;

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
    options.Scope.Add("offline_access");

    options.ClaimActions.Remove("amr");
    options.ClaimActions.MapUniqueJsonKey("website", "website");

    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true;

    // .NET 9 feature
    options.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Require;

    options.TokenValidationParameters.NameClaimType = "name";
    options.TokenValidationParameters.RoleClaimType = "role";
});

Microsoft identity 공급자 구현

Microsoft에는 여러 identity 공급자와 OpenID Connect 구현이 있습니다. Microsoft에는 다른 OpenID Connect 서버가 있습니다.

  • Microsoft Entra ID
  • Microsoft Entra 외부 ID
  • Azure AD B2C

ASP.NET Core에서 Microsoft identity 공급자 중 하나를 사용하여 인증하는 경우 Microsoft를Identity 사용하는 것이 좋습니다. 웹 Nuget 패키지.

Microsoft.Identity. Web Nuget 패키지는 기본 클라이언트에 대한 일부 변경 내용이 있는 ASP.NET Core OpenID Connect 클라이언트에서 맨 위에 빌드된 Microsoft 특정 클라이언트입니다.

타사 OpenID Connect 공급자 클라이언트 사용

많은 OpenID Connect 서버 구현은 동일한 OpenID Connect 구현에 최적화된 Nuget 패키지를 만듭니다. 이러한 패키지는 특정 OpenID Connect 서버에 필요한 추가 기능으로 OpenID Connect 클라이언트 관련 사항을 구현합니다. Microsoft.Identity. 웹은 이것의 한 예입니다.

단일 애플리케이션에서 여러 OpenID Connect 서버에서 여러 OpenID Connect 클라이언트를 구현하는 경우 일반적으로 다른 클라이언트가 다른 클라이언트에 영향을 미치는 일부 옵션을 덮어쓰기 때문에 기본 ASP.NET Core 구현으로 되돌리는 것이 좋습니다.

OpenIddict 웹 공급자 는 다양한 서버 구현을 지원하는 클라이언트 구현입니다.

IdentityModel 은 클레임 기반 identity, OAuth 2.0 및 OpenID Connect용 .NET 표준 도우미 라이브러리입니다. 클라이언트 구현에 도움이 되는 데도 사용할 수 있습니다.

BFF(프런트 엔드) 보안 아키텍처용 백 엔드

웹 애플리케이션에 대해 OpenID Connect 퍼블릭 클라이언트를 구현하는 것은 더 이상 권장되지 않습니다.

자세한 내용은 브라우저 기반 애플리케이션에 대한 초안 OAuth 2.0을 참조하세요.

독립 백 엔드가 없는 웹 애플리케이션을 구현하는 경우 BFF(백 엔드 for Frontend) 패턴 보안 아키텍처를 사용하는 것이 좋습니다. 이 패턴은 여러 가지 방법으로 구현할 수 있지만 인증은 항상 백 엔드에서 구현되며 추가 권한 부여 또는 인증 흐름을 위해 중요한 데이터가 웹 클라이언트로 전송되지 않습니다.

고급 기능, 표준, OIDC 클라이언트 확장

로깅

OpenID Connect 클라이언트 디버깅은 어려울 수 있습니다. PII(개인 식별 정보) 데이터는 기본적으로 기록되지 않습니다. 개발 모드에서 디버깅하는 경우 ** IdentityModelEventSource.ShowPII**를 사용하여 중요한 개인 데이터를 기록할 수 있습니다. 생산적인 서버에 배포하면 안 됩니다.

//using ...

using Microsoft.IdentityModel.Logging;

var builder = WebApplication.CreateBuilder(args);

//... code 

var app = builder.Build();

IdentityModelEventSource.ShowPII = true;

//... code 

app.Run();

로깅에 대한 자세한 내용은 로깅을 참조하세요.

참고 항목

구성된 로그 수준을 낮추어 필요한 모든 로그를 볼 수 있습니다.

OIDC 및 OAuth 매개 변수 사용자 지정

OAuth 및 OIDC 인증 처리기 AdditionalAuthorizationParameters 옵션을 사용하면 일반적으로 리디렉션 쿼리 문자열의 일부로 포함된 권한 부여 메시지 매개 변수를 사용자 지정할 수 있습니다.

OpenID Connect에서 클레임 매핑

다음 문서를 참조하세요.

ASP.NET Core에서 클레임 매핑, 사용자 지정 및 변환

Blazor OpenID Connect

다음 문서를 참조하세요.

OIDC(OpenID Connect)를 사용하여 ASP.NET Core Blazor Web App 보호

표준

OpenID Connect 1.0

OAuth 공용 클라이언트의 코드 교환에 대한 증명 키

OAuth 2.0 권한 부여 프레임워크

OAuth 2.0 PAR(푸시된 권한 부여 요청) RFC 9126