인증 및 권한 부여
팁
이 콘텐츠는 ‘.NET MAUI를 사용하는 엔터프라이즈 애플리케이션 패턴’ eBook에서 발췌한 것으로, .NET Docs에서 제공되거나 오프라인으로 읽을 수 있는 다운로드 가능한 무료 PDF로 제공됩니다.
인증은 사용자로부터 이름 및 암호와 같은 식별 자격 증명을 획득하고 특정 권한과 대조해 해당 자격 증명의 유효성을 검사하는 프로세스입니다. 자격 증명이 유효한 경우 자격 증명을 제출한 엔터티는 인증된 ID로 간주됩니다. ID가 설정되면 권한 부여 프로세스는 해당 ID가 특정 리소스에 액세스할 수 있는지 여부를 확인합니다.
ASP.NET Core ID, 외부 인증 공급자(예: Microsoft, Google, Facebook 또는 Twitter) 및 인증 미들웨어를 포함해 ASP.NET 웹 애플리케이션과 통신하는 .NET MAUI 앱에 인증 및 권한 부여를 통합하는 방법은 여러 가지가 있습니다. eShop 다중 플랫폼 앱은 IdentityServer를 사용하는 컨테이너화된 ID 마이크로 서비스를 통해 인증 및 권한 부여를 수행합니다. 앱은 IdentityServer에서 보안 토큰을 요청하여 사용자를 인증하거나 리소스에 액세스합니다. IdentityServer가 사용자를 대신하여 토큰을 발급하려면 사용자가 IdentityServer에 로그인해야 합니다. 그러나 IdentityServer는 인증을 위해 사용자 인터페이스 또는 데이터베이스를 제공하지 않습니다. 따라서 eShop 참조 애플리케이션에서는 ASP.NET Core ID가 이 목적으로 사용됩니다.
인증
애플리케이션이 현재 사용자의 ID를 알아야 하는 경우 인증이 필요합니다. 사용자를 식별하는 ASP.NET Core의 기본 메커니즘은 개발자가 구성한 데이터 저장소에 사용자 정보를 저장하는 ASP.NET Core ID 멤버 자격 시스템입니다. 일반적으로 이 데이터 저장소는 EntityFramework 저장소이지만 사용자 지정 저장소 또는 타사 패키지를 사용하여 Azure Storage, DocumentDB 또는 기타 위치에 ID 정보를 저장할 수 있습니다.
로컬 사용자 데이터 저장소를 사용하고 (ASP.NET 웹 애플리케이션에서 전형적인 방식인) 쿠키를 통해 요청 간에 ID 정보를 유지하는 인증 시나리오의 경우 ASP.NET Core ID는 적합한 솔루션입니다. 그러나 쿠키는 데이터를 유지하고 전송하는 자연스러운 방법이 아닐 때도 있습니다. 예를 들어 앱에서 액세스하는 RESTful 엔드포인트를 노출하는 ASP.NET Core 웹 애플리케이션은 이 시나리오에서 쿠키를 사용할 수 없으므로 일반적으로 전달자 토큰 인증을 사용해야 합니다. 그러나 전달자 토큰을 쉽게 검색하고 앱에서 만든 웹 요청의 권한 부여 헤더에 포함할 수 있습니다.
IdentityServer를 사용하여 전달자 토큰 발급
IdentityServer는 ASP.NET Core에 대한 오픈 소스 OpenID Connect 및 OAuth 2.0 프레임워크에 속하며, 로컬 ASP.NET Core ID 사용자에 대한 보안 토큰 발급을 포함하여 많은 인증 및 권한 부여 시나리오에 사용할 수 있습니다.
참고 항목
OpenID Connect와 OAuth 2.0은 매우 비슷하지만 책임이 다릅니다.
OpenID Connect는 OAuth 2.0 프로토콜을 기반으로 하는 인증 계층입니다. OAuth 2는 애플리케이션이 보안 토큰 서비스에서 액세스 토큰을 요청하고 이를 사용하여 API와 통신할 수 있도록 하는 프로토콜입니다. 이 위임은 인증 및 권한 부여를 중앙 집중화할 수 있으므로 클라이언트 애플리케이션과 API의 복잡성을 줄입니다.
OpenID Connect 및 OAuth 2.0은 인증과 API 액세스의 두 가지 기본 보안 문제를 결합하며 IdentityServer는 이러한 프로토콜을 구현한 것입니다.
eShop 참조 애플리케이션과 같이 클라이언트-마이크로 서비스 간 직접 통신을 사용하는 애플리케이션에서는 다음 다이어그램에서 보는 것처럼 STS(보안 토큰 서비스)로 작동하는 전용 인증 마이크로 서비스를 사용하여 사용자를 인증할 수 있습니다. 클라이언트-마이크로 서비스 간 직접 통신에 관한 자세한 내용은 마이크로 서비스를 참조하세요.
eShop 다중 플랫폼 앱은 IdentityServer를 사용하여 인증 및 API에 대한 액세스 제어를 수행하는 ID 마이크로 서비스와 통신합니다. 따라서 다중 플랫폼 앱은 사용자를 인증하거나 리소스에 액세스하기 위해 IdentityServer에서 토큰을 요청합니다.
- IdentityServer를 사용하여 사용자를 인증하는 작업은 인증 프로세스의 결과를 나타내는 ID 토큰을 요청하는 다중 플랫폼 앱에서 수행합니다. 최소한 사용자의 식별자와 사용자를 인증하는 방법 및 시기에 관한 정보가 포함됩니다. 이는 추가 ID 데이터를 포함할 수도 있습니다.
- IdentityServer를 사용하여 리소스에 액세스하는 작업은 API 리소스에 대한 액세스를 허용하는 액세스 토큰을 요청하는 다중 플랫폼 앱에서 수행합니다. 클라이언트는 액세스 토큰을 요청하여 이를 API에 전달합니다. 액세스 토큰에는 클라이언트 및 사용자(있는 경우)에 관한 정보가 포함됩니다. 그런 다음, API는 해당 정보를 사용하여 데이터에 대한 액세스 권한을 부여합니다.
참고
토큰을 성공적으로 요청하려면 먼저 클라이언트를 IdentityServer에 등록해야 합니다. 클라이언트 추가에 관한 자세한 내용은 클라이언트 정의를 참조하세요.
웹 애플리케이션에 IdentityServer 추가
ASP.NET Core 웹 애플리케이션이 IdentityServer를 사용하려면 웹 애플리케이션의 Visual Studio 솔루션에 추가해야 합니다. 자세한 내용은 IdentityServer 설명서의 설정 및 개요를 참조하세요.
IdentityServer가 웹 애플리케이션의 Visual Studio 솔루션에 포함되면 OpenID Connect 및 OAuth 2.0 엔드포인트에 대한 요청을 처리하기 위해 HTTP 요청 처리 파이프라인에 추가해야 합니다. 이는 다음 코드 예제와 같이 Identity.API
프로젝트의 Program.cs에서 구성됩니다.
...
app.UseIdentityServer();
순서는 웹 애플리케이션의 HTTP 요청 처리 파이프라인에서 중요합니다. 따라서 로그인 화면을 구현하는 UI 프레임워크에 앞서 IdentityServer를 파이프라인에 추가해야 합니다.
IdentityServer 구성
IdentityServer는 eShop 참조 애플리케이션의 다음 코드 예제에 설명된 대로 AddIdentityServer
메서드를 호출하여 Identity.API
프로젝트의 Program.cs를 구성합니다.
builder.Services.AddIdentityServer(options =>
{
options.Authentication.CookieLifetime = TimeSpan.FromHours(2);
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
// TODO: Remove this line in production.
options.KeyManagement.Enabled = false;
})
.AddInMemoryIdentityResources(Config.GetResources())
.AddInMemoryApiScopes(Config.GetApiScopes())
.AddInMemoryApiResources(Config.GetApis())
.AddInMemoryClients(Config.GetClients(builder.Configuration))
.AddAspNetIdentity<ApplicationUser>()
// TODO: Not recommended for production - you need to store your key material somewhere secure
.AddDeveloperSigningCredential();
services.AddIdentityServer
메서드를 호출한 후 다음을 구성하기 위해 추가 흐름 API가 호출됩니다.
- 서명에 사용되는 자격 증명
- 사용자의 요청에 따라 액세스할 수 있는 API 및 ID 리소스
- 토큰을 요청하기 위해 연결되는 클라이언트
- ASP.NET Core ID
팁
IdentityServer 구성을 동적으로 로드합니다. IdentityServer의 API를 사용하면 구성 개체의 메모리 내 목록에서 IdentityServer를 구성할 수 있습니다. eShop 참조 애플리케이션에서 이러한 메모리 내 컬렉션은 애플리케이션에 하드 코딩됩니다. 그러나 프로덕션 시나리오에서 이러한 컬렉션은 구성 파일 또는 데이터베이스에서 동적으로 로드할 수 있습니다.
ASP.NET Core ID를 사용하도록 IdentityServer를 구성하는 방법에 관한 자세한 내용은 IdentityServer 설명서에서 ASP.NET Core ID 사용을 참조하세요.
API 리소스 구성
API 리소스를 구성할 때 AddInMemoryApiResources
메서드는 IEnumerable<ApiResource>
컬렉션을 예상합니다. 다음 코드 예는 eShop 참조 애플리케이션에서 이 컬렉션을 제공하는 GetApis
메서드를 보여 줍니다.
public static IEnumerable<ApiResource> GetApis()
{
return new List<ApiResource>
{
new ApiScope("orders", "Orders Service"),
new ApiScope("basket", "Basket Service"),
new ApiScope("webhooks", "Webhooks registration Service"),
};
}
이 메서드는 IdentityServer가 순서와 basket API를 보호하도록 지정합니다. 따라서 이러한 API를 호출할 때에는 IdentityServer 관리형 액세스 토큰이 필요합니다. ApiResource
형식에 관한 자세한 내용은 IdentityServer 설명서의 API 리소스를 참조하세요.
ID 리소스 구성
ID 리소스를 구성할 때 AddInMemoryIdentityResources
메서드는 IEnumerable<IdentityResource>
컬렉션을 예상합니다. ID 리소스는 사용자 ID, 이름 또는 이메일 주소와 같은 데이터입니다. 각 ID 리소스에는 고유한 이름이 있고 임의의 클레임 형식을 할당할 수 있는데, 이는 사용자의 ID 토큰에 포함됩니다. 다음 코드 예는 eShop 참조 애플리케이션에서 이 컬렉션을 제공하는 GetResources
메서드를 보여 줍니다.
public static IEnumerable<IdentityResource> GetResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
OpenID Connect 사양은 일부 표준 ID 리소스를 지정합니다. 최소 요구 사항은 사용자에 대한 고유 ID를 내보내기 위한 지원이 제공된다는 것입니다. IdentityResources.OpenId
ID 리소스를 노출하여 이 작업을 수행합니다.
참고
IdentityResources 클래스는 OpenID Connect 사양(openid, 이메일, 프로필, 전화 및 주소)에 정의된 모든 범위를 지원합니다.
IdentityServer는 사용자 지정 ID 리소스 정의도 지원합니다. 자세한 내용은 IdentityServer 설명서에서 사용자 지정 ID 리소스 정의를 참조하세요. IdentityResource 형식에 관한 자세한 내용은 IdentityServer 설명서의 ID 리소스를 참조하세요.
클라이언트 구성
클라이언트는 IdentityServer에서 토큰을 요청할 수 있는 애플리케이션입니다. 일반적으로 각 클라이언트에 대해 최소한 다음과 같은 설정을 정의해야 합니다.
- 고유한 클라이언트 ID
- 토큰 서비스와 허용되는 상호 작용(‘권한 부여 유형’이라고 함)
- ID 및 액세스 토큰이 전송되는 위치(‘리디렉션 URI’라고 함)
- 클라이언트가 액세스할 수 있는 리소스 목록(‘범위’라고 함)
클라이언트를 구성할 때 AddInMemoryClients
메서드는 IEnumerable<Client>
컬렉션을 예상합니다. 다음 코드 예는 eShop 참조 애플리케이션에서 이 컬렉션을 제공하는 GetClients
메서드의 eShop 다중 플랫폼 앱에 대한 구성을 보여 줍니다.
public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{
return new List<Client>
{
// Omitted for brevity
new Client
{
ClientId = "maui",
ClientName = "eShop MAUI OpenId Client",
AllowedGrantTypes = GrantTypes.Code,
//Used to retrieve the access token on the back channel.
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { configuration["MauiCallback"] },
RequireConsent = false,
RequirePkce = true,
PostLogoutRedirectUris = { $"{configuration["MauiCallback"]}/Account/Redirecting" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
"orders",
"basket",
"mobileshoppingagg",
"webhooks"
},
//Allow requesting refresh tokens for long lived API access
AllowOfflineAccess = true,
AllowAccessTokensViaBrowser = true,
AlwaysIncludeUserClaimsInIdToken = true,
AccessTokenLifetime = 60 * 60 * 2, // 2 hours
IdentityTokenLifetime = 60 * 60 * 2 // 2 hours
}
};
}
이 구성은 다음 속성에 대한 데이터를 지정합니다.
속성 | 설명 |
---|---|
ClientId |
클라이언트의 고유 ID |
ClientName |
로깅 및 동의 화면에 사용되는 클라이언트 표시 이름 |
AllowedGrantTypes |
클라이언트가 필요에 따라 IdentityServer와 상호 작용하는 방법을 지정합니다. 자세한 내용은 인증 흐름 구성을 참조하세요. |
ClientSecrets |
토큰 엔드포인트에서 토큰을 요청할 때 사용되는 클라이언트 암호 자격 증명을 지정합니다. |
RedirectUris |
토큰 또는 인증 코드를 반환할 수 있는 URI를 지정합니다. |
RequireConsent |
동의 화면이 필요한지 여부를 지정합니다. |
RequirePkce |
인증 코드를 사용하는 클라이언트가 증명 키를 보내야 하는지 여부를 지정합니다. |
PostLogoutRedirectUris |
로그아웃 후 리디렉션할 수 있는 URI를 지정합니다. |
AllowedCorsOrigins |
IdentityServer가 원본에서 원본 간 호출을 허용할 수 있도록 클라이언트의 원본을 지정합니다. |
AllowedScopes |
클라이언트가 액세스할 수 있는 리소스를 지정합니다. 기본적으로 클라이언트는 리소스에 액세스할 수 없습니다. |
AllowOfflineAccess |
클라이언트가 새로 고침 토큰을 요청할 수 있는지 여부를 지정합니다. |
AllowAccessTokensViaBrowser |
클라이언트가 브라우저 창에서 액세스 토큰을 받을 수 있는지 여부를 지정합니다. |
AlwaysIncludeUserClaimsInIdToken |
사용자 클레임이 항상 ID 토큰에 추가되도록 지정합니다. 기본적으로 이는 userinfo 엔드포인트를 사용하여 검색해야 합니다. |
AccessTokenLifetime |
액세스 토큰의 수명을 초 단위로 지정합니다. |
IdentityTokenLifetime |
ID 토큰의 수명을 초 단위로 지정합니다. |
인증 흐름 구성
클라이언트와 IdentityServer 간의 인증 흐름은 Client.AllowedGrantTypes
속성에 권한 부여 유형을 지정하여 구성할 수 있습니다. OpenID Connect 및 OAuth 2.0 사양은 다음을 포함한 여러 인증 흐름을 정의합니다.
인증 흐름 | 설명 |
---|---|
암시적 | 이 흐름은 브라우저 기반 애플리케이션에 최적화되어 있으며 사용자 인증 전용 또는 인증 및 액세스 토큰 요청에 사용해야 합니다. 모든 토큰은 브라우저를 통해 전송되므로 새로 고침 토큰과 같은 고급 기능은 허용되지 않습니다. |
인증 코드 | 이 흐름은 클라이언트 인증을 지원하면서 브라우저 전면 채널이 아닌 백 채널에서 토큰을 검색하는 기능을 제공합니다. |
하이브리드 | 이 흐름은 암시적 코드 부여 형식과 인증 코드 부여 형식의 조합입니다. ID 토큰은 브라우저 채널을 통해 전송되며 서명된 프로토콜 응답 및 인증 코드와 같은 기타 아티팩트를 포함합니다. 응답의 유효성을 성공적으로 검사한 후 백 채널을 사용하여 액세스 및 새로 고침 토큰을 검색해야 합니다. |
팁
하이브리드 인증 흐름을 사용하는 것이 좋습니다. 하이브리드 인증 흐름은 브라우저 채널에 가해지는 여러 공격을 완화하며 액세스 토큰(및 가능하다면 새로 고침 토큰)을 검색하려는 네이티브 애플리케이션에 권장되는 흐름입니다.
인증 흐름에 관한 자세한 내용은 IdentityServer 설명서의 권한 부여 유형을 참조하세요.
인증 수행
IdentityServer가 사용자를 대신하여 토큰을 발급하려면 사용자가 IdentityServer에 로그인해야 합니다. 그러나 IdentityServer는 인증을 위해 사용자 인터페이스 또는 데이터베이스를 제공하지 않습니다. 따라서 eShop 참조 애플리케이션에서는 ASP.NET Core ID가 이 목적으로 사용됩니다.
eShop 다중 플랫폼 앱은 아래 다이어그램에 설명된 하이브리드 인증 흐름을 사용하여 IdentityServer로 인증합니다.
<base endpoint>:5105/connect/authorize
에 대한 로그인 요청이 이루어집니다. 인증에 성공한 후 IdentityServer는 인증 코드와 ID 토큰이 포함된 인증 응답을 반환합니다. 인증 코드는 액세스, ID 및 새로 고침 토큰으로 응답하는 <base endpoint>:5105/connect/token
으로 전송됩니다.
eShop 다중 플랫폼 앱은 추가 매개 변수와 함께 <base endpoint>:5105/connect/endsession
에 요청을 보내 IdentityServer에서 로그아웃됩니다. 로그아웃 후 IdentityServer는 로그아웃 후 리디렉션 URI를 다중 플랫폼 앱으로 다시 전송하여 응답합니다. 이 프로세스를 다이어그램으로 나타내면 아래와 같습니다.
eShop 다중 플랫폼 앱에서 IdentityServer와의 통신은 IIdentityService
인터페이스를 구현하는 IdentityService
클래스에 의해 수행됩니다. 이 인터페이스는 구현 클래스가 SignInAsync
, SignOutAsync
, GetUserInfoAsync
및 GetAuthTokenAsync
메서드를 제공해야 한다고 지정합니다.
로그인
사용자가 LoginView
의 LOGIN
단추를 탭하면 LoginViewModel
클래스의 SignInCommand
가 실행되어 SignInAsync
메서드가 실행됩니다. 다음 코드 예제에서는 이 메서드를 보여줍니다.
[RelayCommand]
private async Task SignInAsync()
{
await IsBusyFor(
async () =>
{
var loginSuccess = await _appEnvironmentService.IdentityService.SignInAsync();
if (loginSuccess)
{
await NavigationService.NavigateToAsync("//Main/Catalog");
}
});
}
이 메서드는 다음 코드 예제에서 보는 것처럼 IdentityService
클래스에서 SignInAsync
메서드를 호출합니다.
public async Task<bool> SignInAsync()
{
var response = await GetClient().LoginAsync(new LoginRequest()).ConfigureAwait(false);
if (response.IsError)
{
return false;
}
await _settingsService
.SetUserTokenAsync(
new UserToken
{
AccessToken = response.AccessToken,
IdToken = response.IdentityToken,
RefreshToken = response.RefreshToken,
ExpiresAt = response.AccessTokenExpiration
})
.ConfigureAwait(false);
return !response.IsError;
}
IdentityService
는 IdentityModel.OidcClient
NuGet 패키지와 함께 제공되는 OidcClient
를 사용합니다. 이 클라이언트는 애플리케이션의 사용자에게 인증 웹 보기를 표시하고 인증 결과를 캡처합니다. 클라이언트는 필수 매개 변수를 사용하여 IdentityServer의 권한 부여 엔드포인트에 대한 URI에 연결합니다. 권한 부여 엔드포인트는 사용자 설정으로 노출되는 기본 엔드포인트의 포트 5105에서 /connect/authorize
에 위치합니다. 사용자 설정에 관한 자세한 내용은 구성 관리를 참조하세요.
참고 항목
OAuth에 대한 PKCE(Proof Key for Code Exchange) 확장을 구현하여 eShop 다중 플랫폼 앱의 공격 표면이 줄어듭니다. PKCE는 가로챈 인증 코드를 함부로 사용하지 못하도록 보호합니다. 이러한 보호는 클라이언트가 비밀 검증 도구 즉, 권한 부여 요청에 전달되는 해시를 생성하여 이루어지며, 이 해시는 인증 코드를 사용할 때 해시되지 않은 상태로 표시됩니다. PKCE에 관한 자세한 내용은 인터넷 엔지니어링 태스크 포스 웹 사이트에서 OAuth 공용 클라이언트의 코드 교환에 대한 증명 키를 참조하세요.
토큰 엔드포인트가 유효한 인증 정보, 인증 코드 및 PKCE 비밀 검증자를 수신하면 액세스 토큰, ID 토큰 및 새로 고침 토큰으로 응답합니다. 액세스 토큰(API 리소스에 대한 액세스를 허용)과 ID 토큰은 애플리케이션 설정으로 저장되며 페이지 탐색을 수행합니다. 따라서 eShop 다중 플랫폼 앱의 전반적인 효과는 다음과 같습니다. 사용자는 IdentityServer를 사용하여 인증에 성공할 수 있는 경우 //Main/Catalog
경로를 탐색합니다. 이 경로는 CatalogView
를 선택한 탭으로 표시하는 TabbedPage
입니다.
탐색에 관한 자세한 내용은 탐색을 참조하세요. WebView 탐색으로 인해 뷰 모델 메서드가 실행되는 과정에 관한 자세한 내용은 동작을 사용하여 탐색 호출을 참조하세요. 애플리케이션 설정에 관한 자세한 내용은 구성 관리를 참조하세요.
참고 항목
eShop은 또한 앱이 SettingsView
에서 모의 서비스를 사용하도록 구성된 경우 모의 로그인을 허용합니다. 이 모드에서는 앱이 IdentityServer와 통신하지 않으며, 그 대신 사용자가 자격 증명을 사용하여 로그인할 수 있도록 허용합니다.
로그아웃
사용자가 ProfileView
의 LOG OUT
단추를 탭하면 ProfileViewModel
클래스의 LogoutCommand
가 실행되어 LogoutAsync
메서드가 실행됩니다. 이 메서드는 LoginView
페이지에 대한 페이지 탐색을 수행하고 true
로 설정된 Logout
쿼리 매개 변수를 전달합니다.
해당 매개 변수는 ApplyQueryAttributes
메서드에서 평가됩니다. Logout
매개 변수가 true
값과 함께 존재하는 경우 LoginViewModel
클래스의 PerformLogoutAsync
메서드가 실행됩니다. 이는 다음 코드 예에 나와 있습니다.
private async Task PerformLogoutAsync()
{
await _appEnvironmentService.IdentityService.SignOutAsync();
_settingsService.UseFakeLocation = false;
UserName.Value = string.Empty;
Password.Value = string.Empty;
}
이 메서드는 IdentityService
클래스의 SignOutAsync
메서드를 호출합니다. 이 메서드는 OidcClient
를 호출하여 사용자 세션을 종료하고 저장된 사용자 토큰을 모두 지웁니다. 애플리케이션 설정에 관한 자세한 내용은 구성 관리를 참조하세요. 다음 코드 예제는 SignOutAsync
메서드를 보여줍니다.
public async Task<bool> SignOutAsync()
{
var response = await GetClient().LogoutAsync(new LogoutRequest()).ConfigureAwait(false);
if (response.IsError)
{
return false;
}
await _settingsService.SetUserTokenAsync(default);
return !response.IsError;
}
이 메서드는 OidcClient
를 사용하여 필수 매개 변수와 함께 IdentityServer의 세션 종료 엔드포인트에 대한 URI를 호출합니다. 최종 세션 엔드포인트는 사용자 설정으로 노출되는 기본 엔드포인트의 포트 5105에서 /connect/endsession
에 위치합니다. 사용자가 성공적으로 로그아웃하면 LoginView
가 사용자에게 표시되고 저장된 사용자 정보가 모두 지워집니다.
탐색에 관한 자세한 내용은 탐색을 참조하세요. WebView
탐색으로 인해 뷰 모델 메서드가 실행되는 과정에 관한 자세한 내용은 동작을 사용하여 탐색 호출을 참조하세요. 애플리케이션 설정에 관한 자세한 내용은 구성 관리를 참조하세요.
참고 항목
eShop은 또한 앱이 SettingsView
에서 모의 서비스를 사용하도록 구성된 경우 모의 로그아웃을 허용합니다. 이 모드에서는 앱이 IdentityServer와 통신하지 않고 그 대신 애플리케이션 설정에서 저장된 토큰을 지웁니다.
권한 부여
인증 후 ASP.NET Core 웹 API는 액세스 권한을 부여해야 하는 경우가 많으며, 이를 통해 서비스는 모든 사용자가 아닌 일부 인증된 사용자에게 API를 제공합니다.
다음 코드 예제와 같이 컨트롤러 또는 작업에 대한 액세스 권한을 인증된 사용자에게만 부여하는 Authorize 특성을 컨트롤러 또는 작업에 적용하여 ASP.NET Core 경로에 대한 액세스를 제한할 수 있습니다.
[Authorize]
public sealed class BasketController : Controller
{
// Omitted for brevity
}
권한이 없는 사용자가 Authorize 특성으로 표시된 컨트롤러 또는 작업에 액세스하려고 하면 API 프레임워크는 401 (unauthorized)
HTTP 상태 코드를 반환합니다.
참고
API를 특정 사용자에게만 제공하기 위해 Authorize 특성에 매개 변수를 지정할 수 있습니다. 자세한 내용은 ASP.NET Core 문서: 권한 부여를 참조하세요.
액세스 토큰이 제어 권한을 제공하도록 IdentityServer를 권한 부여 워크플로에 통합할 수 있습니다. 이 방법은 아래 다이어그램에 나와 있습니다.
eShop 다중 플랫폼 앱은 ID 마이크로 서비스와 통신하고 인증 프로세스의 일부로 액세스 토큰을 요청합니다. 그런 다음 액세스 토큰은 액세스 요청의 일부로서 주문 및 basket 마이크로 서비스에 의해 노출되는 API에 전달됩니다. 액세스 토큰에는 클라이언트 및 사용자에 관한 정보가 포함됩니다. 그런 다음, API는 해당 정보를 사용하여 데이터에 대한 액세스 권한을 부여합니다. API를 보호하도록 IdentityServer를 구성하는 방법에 관한 자세한 내용은 API 리소스 구성을 참조하세요.
권한 부여를 수행하도록 IdentityServer를 구성
IdentityServer를 사용하여 권한 부여를 수행하려면 해당 권한 부여 미들웨어를 웹 애플리케이션의 HTTP 요청 파이프라인에 추가해야 합니다. 미들웨어는 Program
클래스의 AddApplicationServices
메서드에서 호출되고 eShop 참조 애플리케이션의 다음 코드 예에서 설명되는 AddDefaultAuthentication
확장 메서드에 추가됩니다.
public static IServiceCollection AddDefaultAuthentication(this IHostApplicationBuilder builder)
{
var services = builder.Services;
var configuration = builder.Configuration;
var identitySection = configuration.GetSection("Identity");
if (!identitySection.Exists())
{
// No identity section, so no authentication
return services;
}
// prevent from mapping "sub" claim to nameidentifier.
JsonWebTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
services.AddAuthentication().AddJwtBearer(options =>
{
var identityUrl = identitySection.GetRequiredValue("Url");
var audience = identitySection.GetRequiredValue("Audience");
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
options.Audience = audience;
options.TokenValidationParameters.ValidIssuers = [identityUrl];
options.TokenValidationParameters.ValidateAudience = false;
});
services.AddAuthorization();
return services;
}
이 메서드는 유효한 액세스 토큰으로만 API에 액세스할 수 있도록 합니다. 미들웨어는 들어오는 토큰의 유효성을 검사하여 신뢰할 수 있는 발급자로부터 전송되었는지 확인하고 토큰을 수신하는 API와 함께 사용할 수 있는지 확인합니다. 따라서 주문 또는 basket 컨트롤러로 검색하면 액세스 토큰이 필요함을 나타내는 401 (unauthorized)
HTTP 상태 코드가 반환됩니다.
API에 대한 액세스 요청 수행
주문 및 basket 마이크로 서비스를 요청할 때 다음 코드 예제와 같이 인증 프로세스 중에 IdentityServer에서 가져온 액세스 토큰을 요청에 포함해야 합니다.
public async Task CreateOrderAsync(Models.Orders.Order newOrder)
{
var authToken = await _identityService.GetAuthTokenAsync().ConfigureAwait(false);
if (string.IsNullOrEmpty(authToken))
{
return;
}
var uri = $"{UriHelper.CombineUri(_settingsService.GatewayOrdersEndpointBase, ApiUrlBase)}?api-version=1.0";
var success = await _requestProvider.PostAsync(uri, newOrder, authToken, "x-requestid").ConfigureAwait(false);
}
액세스 토큰은 IIdentityService
구현으로 저장되며 GetAuthTokenAsync
메서드를 사용하여 검색할 수 있습니다.
마찬가지로 다음 코드 예제와 같이 IdentityServer로 보호된 API로 데이터를 보낼 때 액세스 토큰을 포함해야 합니다.
public async Task ClearBasketAsync()
{
var authToken = await _identityService.GetAuthTokenAsync().ConfigureAwait(false);
if (string.IsNullOrEmpty(authToken))
{
return;
}
await GetBasketClient().DeleteBasketAsync(new DeleteBasketRequest(), CreateAuthenticationHeaders(authToken))
.ConfigureAwait(false);
}
액세스 토큰은 IIdentityService
에서 검색되어 BasketService
클래스의 ClearBasketAsync
메서드 호출에 포함됩니다.
eShop 다중 플랫폼 앱의 RequestProvider
클래스는 HttpClient
클래스를 사용하여 eShop 참조 애플리케이션에 의해 노출된 RESTful API에 요청합니다. 권한 부여가 필요한 주문 및 basket API를 요청할 때 유효한 액세스 토큰을 요청에 포함해야 합니다. 이는 다음 코드 예제에 설명된 대로 HttpClient 인스턴스의 헤더에 액세스 토큰을 추가하여 수행합니다.
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpClient
클래스의 DefaultRequestHeaders
속성은 각 요청과 함께 전송되는 헤더를 노출하며, 액세스 토큰은 Bearer
를 문자열의 접두사로 하는 Authorization
헤더에 추가됩니다. 요청이 RESTful API로 전송되면 Authorization
헤더의 값이 추출되며, 그 값을 신뢰할 수 있는 발급자에게서 전송하여 사용자가 이를 수신하는 API를 호출할 수 있는 권한이 있는지 여부를 확인하는 데 사용하도록 유효성 검사가 진행됩니다.
eShop 다중 플랫폼 앱이 웹 요청을 수행하는 방법에 대한 자세한 내용은 원격 데이터 액세스를 참조하세요.
요약
ASP.NET 웹 애플리케이션과 통신하는 .NET MAUI 앱에 인증 및 권한 부여를 통합하는 방법에는 여러 가지가 있습니다. eShop 다중 플랫폼 앱은 IdentityServer를 사용하는 컨테이너화된 ID 마이크로 서비스를 통해 인증 및 권한 부여를 수행합니다. IdentityServer는 전달자 토큰 인증을 수행하기 위해 ASP.NET Core ID와 통합되는 ASP.NET Core에 대한 오픈 소스 OpenID Connect 및 OAuth 2.0 프레임워크입니다.
다중 플랫폼 앱은 IdentityServer에서 보안 토큰을 요청하여 사용자를 인증하거나 리소스에 액세스합니다. 리소스에 액세스할 때 권한 부여가 필요한 API에 대한 요청에 액세스 토큰을 포함해야 합니다. IdentityServer의 미들웨어는 들어오는 액세스 토큰의 유효성을 검사하여 신뢰할 수 있는 발급자에게서 전송되고 이를 수신하는 API와 함께 사용할 수 있는지 확인합니다.
.NET