ASP.NET 웹 API에 대한 JWT 인증


264

웹 API 응용 프로그램에서 JWT 베어러 토큰 (JSON 웹 토큰)을 지원하려고하는데 길을 잃었습니다.

.NET Core 및 OWIN 응용 프로그램에 대한 지원을 참조하십시오.
현재 IIS에서 응용 프로그램을 호스팅하고 있습니다.

애플리케이션에서이 인증 모듈을 어떻게 달성 할 수 있습니까? <authentication>양식 / Windows 인증을 사용하는 방법과 유사한 구성을 사용할 수 있는 방법이 있습니까?

답변:


611

이 질문에 대답했습니다. 4 년 전 HMAC를 사용하여 ASP.NET 웹 API를 보호하는 방법 .

이제 보안에서 많은 부분이 변경되었습니다. 특히 JWT가 인기를 얻고 있습니다. 여기서는 JWT를 가장 간단하고 기본적인 방식으로 사용하는 방법을 설명하려고 노력하므로 OWIN, Oauth2, ASP.NET Identity ... :)의 정글에서 길을 잃지 않을 것입니다.

JWT 토큰을 모르는 경우 다음을 조금 살펴 봐야합니다.

https://tools.ietf.org/html/rfc7519

기본적으로 JWT 토큰은 다음과 같습니다.

<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>

예:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1NzI0LCJleHAiOjE0Nzc1NjY5MjQSiZMQQIiQIQIQQIQIQQIQQIQQIQQIQQIQQIQQIQQIQIQQIQQIQIQQIQIQIQIQIQIQIQIQIQIQIQIQIQIQIQIQIQIQIQ

JWT 토큰에는 세 가지 섹션이 있습니다.

  1. 헤더 : Base64로 인코딩 된 JSON 형식
  2. 클레임 : Base64로 인코딩 된 JSON 형식입니다.
  3. 서명 : Base64로 인코딩 된 헤더 및 클레임을 기반으로 만들고 서명했습니다.

위의 토큰과 함께 jwt.io 웹 사이트를 사용하면 토큰을 해독하여 아래와 같이 볼 수 있습니다.

여기에 이미지 설명을 입력하십시오

기술적으로 JWT는 헤더에서 서명 된 서명과 헤더에 지정된 보안 알고리즘으로 클레임을 사용합니다 (예 : HMACSHA256). 따라서 클레임에 민감한 정보를 저장하는 경우 HTTP를 통해 JWT를 전송해야합니다.

이제 JWT 인증을 사용하기 위해 레거시 Web Api 시스템이있는 경우 실제로 OWIN 미들웨어가 필요하지 않습니다. 간단한 개념은 JWT 토큰을 제공하는 방법과 요청이 올 때 토큰을 확인하는 방법입니다. 그게 다야.

데모로 돌아가서 JWT 토큰을 가볍게 유지하기 위해 JWT 만 저장 username하고 저장 expiration time합니다. 그러나 이런 식으로 역할과 같은 정보를 추가하려면 새로운 로컬 ID (주체)를 다시 작성해야합니다. 역할 권한 부여를 수행하려는 경우. 그러나 JWT에 더 많은 정보를 추가하려는 경우 사용자에게 달려 있습니다. 매우 유연합니다.

OWIN 미들웨어를 사용하는 대신 컨트롤러의 조치를 사용하여 JWT 토큰 엔드 포인트를 제공 할 수 있습니다.

public class TokenController : ApiController
{
    // This is naive endpoint for demo, it should use Basic authentication
    // to provide token or POST request
    [AllowAnonymous]
    public string Get(string username, string password)
    {
        if (CheckUser(username, password))
        {
            return JwtManager.GenerateToken(username);
        }

        throw new HttpResponseException(HttpStatusCode.Unauthorized);
    }

    public bool CheckUser(string username, string password)
    {
        // should check in the database
        return true;
    }
}

이것은 순진한 행동입니다. 프로덕션에서는 POST 요청 또는 기본 인증 엔드 포인트를 사용하여 JWT 토큰을 제공해야합니다.

기반으로 토큰을 생성하는 방법은 username무엇입니까?

System.IdentityModel.Tokens.JwtMicrosoft에서 호출 한 NuGet 패키지 를 사용하여 토큰을 생성하거나 원하는 경우 다른 패키지를 생성 할 수도 있습니다. 데모에서는 다음 HMACSHA256SymmetricKey같이 사용 합니다 .

/// <summary>
/// Use the below code to generate symmetric Secret Key
///     var hmac = new HMACSHA256();
///     var key = Convert.ToBase64String(hmac.Key);
/// </summary>
private const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";

public static string GenerateToken(string username, int expireMinutes = 20)
{
    var symmetricKey = Convert.FromBase64String(Secret);
    var tokenHandler = new JwtSecurityTokenHandler();

    var now = DateTime.UtcNow;
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new[]
        {
            new Claim(ClaimTypes.Name, username)
        }),

        Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),

        SigningCredentials = new SigningCredentials(
            new SymmetricSecurityKey(symmetricKey), 
            SecurityAlgorithms.HmacSha256Signature)
    };

    var stoken = tokenHandler.CreateToken(tokenDescriptor);
    var token = tokenHandler.WriteToken(stoken);

    return token;
}

JWT 토큰을 제공하기위한 엔드 포인트가 완료되었습니다. 이제 요청이 올 때 JWT의 유효성을 검사하는 방법은 무엇입니까? 데모에서 내가 JwtAuthenticationAttribute상속 한 것을 만들었 IAuthenticationFilter습니다 ( 여기의 인증 필터에 대한 자세한 내용 ).

이 속성을 사용하면 모든 작업을 인증 할 수 있습니다.이 속성을 해당 작업에두기 만하면됩니다.

public class ValueController : ApiController
{
    [JwtAuthentication]
    public string Get()
    {
        return "value";
    }
}

WebAPI에 대한 모든 수신 요청의 유효성을 검사하려는 경우 OWIN 미들웨어 또는 DelegateHander를 사용할 수도 있습니다 (컨트롤러 또는 작업에만 해당되지 않음)

다음은 인증 필터의 핵심 방법입니다.

private static bool ValidateToken(string token, out string username)
{
    username = null;

    var simplePrinciple = JwtManager.GetPrincipal(token);
    var identity = simplePrinciple.Identity as ClaimsIdentity;

    if (identity == null)
        return false;

    if (!identity.IsAuthenticated)
        return false;

    var usernameClaim = identity.FindFirst(ClaimTypes.Name);
    username = usernameClaim?.Value;

    if (string.IsNullOrEmpty(username))
       return false;

    // More validate to check whether username exists in system

    return true;
}

protected Task<IPrincipal> AuthenticateJwtToken(string token)
{
    string username;

    if (ValidateToken(token, out username))
    {
        // based on username to get more information from database 
        // in order to build local identity
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, username)
            // Add more claims if needed: Roles, ...
        };

        var identity = new ClaimsIdentity(claims, "Jwt");
        IPrincipal user = new ClaimsPrincipal(identity);

        return Task.FromResult(user);
    }

    return Task.FromResult<IPrincipal>(null);
}

워크 플로는 JWT 라이브러리 (위의 NuGet 패키지)를 사용하여 JWT 토큰의 유효성을 검사 한 다음 되돌아옵니다 ClaimsPrincipal. 사용자가 시스템에 있는지 확인하고 원하는 경우 다른 사용자 지정 유효성 검사를 추가하는 등 더 많은 유효성 검사를 수행 할 수 있습니다. JWT 토큰을 유효성 검증하고 프린시 펄을 다시 가져 오는 코드 :

public static ClaimsPrincipal GetPrincipal(string token)
{
    try
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;

        if (jwtToken == null)
            return null;

        var symmetricKey = Convert.FromBase64String(Secret);

        var validationParameters = new TokenValidationParameters()
        {
            RequireExpirationTime = true,
            ValidateIssuer = false,
            ValidateAudience = false,
            IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
        };

        SecurityToken securityToken;
        var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);

        return principal;
    }
    catch (Exception)
    {
        //should write log
        return null;
    }
}

JWT 토큰의 유효성이 검증되고 프린시 펄이 리턴되면, 새로운 로컬 ID를 빌드하고 역할 권한을 점검하기 위해 추가 정보를 넣어야합니다.

config.Filters.Add(new AuthorizeAttribute());리소스에 대한 익명 요청을 방지하기 위해 전역 범위에서 (기본 인증) 을 추가 해야합니다.

Postman을 사용하여 데모를 테스트 할 수 있습니다.

요청 토큰 (위에서 언급했듯이 데모 용으로 만 해당) :

GET http://localhost:{port}/api/token?username=cuong&password=1

승인 된 요청을 위해 JWT 토큰을 헤더에 넣습니다. 예 :

GET http://localhost:{port}/api/value

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1MjU4LCJleHAiOjE0Nzc1NjY0NTgsImlhdCI6MTQ3NzU2NTI1OH0.dSwwufd4-gztkLpttZsZ1255oEzpWCJkayR_4yvNL1s

데모는 여기에 있습니다 : https://github.com/cuongle/WebApi.Jwt


5
@Cuong Le가 잘 설명했지만 더 추가하고 싶습니다. OWIN을 사용하는 경우 Microsoft.Owin.Security.Jwt에서 사용 가능한 UseJwtBearerAuthentication을 확인하십시오. WebAPI에서이 owin 미들웨어를 사용하여 모든 수신 요청을 자동으로 검증 할 수 있습니다. owin 시작 클래스를 사용하여 미들웨어를 등록하십시오
Jek

5
@AmirPopovich 응답에 토큰을 설정할 필요가 없으며 토큰은 클라이언트 측의 다른 곳에 저장해야합니다. 웹의 경우 HTTP 요청을 보낼 때마다 로컬 저장소에 넣을 수 있으며 토큰을 헤더에 넣을 수 있습니다.
cuongle

7
와우 이것은 내가 오랫동안 본 가장 간단한 설명입니다. 내가 할 수 있다면 +100
gyozo kudor

4
@Homam :이 늦게 대답해서 죄송합니다. 생성하는 가장 좋은 방법은 다음과 같습니다. varhmac = new HMACSHA256();var key = Convert.ToBase64String(hmac.Key);
cuongle

4
CuongLe의 리포지토리의 데모 코드를 사용하는 사람은 권한 부여 헤더가없는 요청이 처리되지 않는 버그가 있음을 알 수 있습니다. 이는 요청이없는 모든 쿼리가 통과 할 수 없음을 의미합니다 (끝점을 보호하지 않음). 이 문제를 해결하기 위해 @magicleon의 풀 요청이 있습니다 : github.com/cuongle/WebApi.Jwt/pull/4
Chucky

11

최소한의 노력으로 (ASP.NET Core와 마찬가지로 간단하게) 달성했습니다.

이를 위해 나는 OWIN Startup.cs파일과 Microsoft.Owin.Security.Jwt라이브러리를 사용 합니다.

앱을 실행 Startup.cs하려면 다음을 수정해야합니다 Web.config.

<configuration>
  <appSettings>
    <add key="owin:AutomaticAppStartup" value="true" />
    ...

어떻게 Startup.cs보아야합니까?

using MyApp.Helpers;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Jwt;
using Owin;

[assembly: OwinStartup(typeof(MyApp.App_Start.Startup))]

namespace MyApp.App_Start
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseJwtBearerAuthentication(
                new JwtBearerAuthenticationOptions
                {
                    AuthenticationMode = AuthenticationMode.Active,
                    TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidAudience = ConfigHelper.GetAudience(),
                        ValidIssuer = ConfigHelper.GetIssuer(),
                        IssuerSigningKey = ConfigHelper.GetSymmetricSecurityKey(),
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true
                    }
                });
        }
    }
}

요즘 많은 사람들이 ASP.NET Core를 사용하고 있으므로 알 수 있듯이 우리가 가지고있는 것과 크게 다르지 않습니다.

그것은 정말로 나를 먼저 당황하게 만들었고, 나는 커스텀 제공자 등을 구현하려고 노력하고있었습니다. 그러나 나는 그것이 그렇게 간단하다고 기대하지 않았습니다. OWIN그냥 바위!

한 가지 언급 할 점-OWIN 시작 NSWag라이브러리를 활성화 한 후에 는 작동하지 않습니다 (예 : 일부 사용자는 Angular 앱에 대한 유형 스크립트 HTTP 프록시를 자동 생성 할 수 있습니다).

또한이 솔루션은 매우 간단했다 - 내가 교체 NSWagSwashbuckle하고 더 이상 문제가되지 않았다.


좋아, 이제 ConfigHelper코드를 공유 하십시오.

public class ConfigHelper
{
    public static string GetIssuer()
    {
        string result = System.Configuration.ConfigurationManager.AppSettings["Issuer"];
        return result;
    }

    public static string GetAudience()
    {
        string result = System.Configuration.ConfigurationManager.AppSettings["Audience"];
        return result;
    }

    public static SigningCredentials GetSigningCredentials()
    {
        var result = new SigningCredentials(GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256);
        return result;
    }

    public static string GetSecurityKey()
    {
        string result = System.Configuration.ConfigurationManager.AppSettings["SecurityKey"];
        return result;
    }

    public static byte[] GetSymmetricSecurityKeyAsBytes()
    {
        var issuerSigningKey = GetSecurityKey();
        byte[] data = Encoding.UTF8.GetBytes(issuerSigningKey);
        return data;
    }

    public static SymmetricSecurityKey GetSymmetricSecurityKey()
    {
        byte[] data = GetSymmetricSecurityKeyAsBytes();
        var result = new SymmetricSecurityKey(data);
        return result;
    }

    public static string GetCorsOrigins()
    {
        string result = System.Configuration.ConfigurationManager.AppSettings["CorsOrigins"];
        return result;
    }
}

또 다른 중요한 측면 - 나는 통해 JWT 토큰을 전송 권한 나 같은 다음를 들어, 헤더 때문에 타이프 라이터 코드 외모 :

(아래 코드는 NSWag에 의해 생성됩니다 )

@Injectable()
export class TeamsServiceProxy {
    private http: HttpClient;
    private baseUrl: string;
    protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;

    constructor(@Inject(HttpClient) http: HttpClient, @Optional() @Inject(API_BASE_URL) baseUrl?: string) {
        this.http = http;
        this.baseUrl = baseUrl ? baseUrl : "https://localhost:44384";
    }

    add(input: TeamDto | null): Observable<boolean> {
        let url_ = this.baseUrl + "/api/Teams/Add";
        url_ = url_.replace(/[?&]$/, "");

        const content_ = JSON.stringify(input);

        let options_ : any = {
            body: content_,
            observe: "response",
            responseType: "blob",
            headers: new HttpHeaders({
                "Content-Type": "application/json", 
                "Accept": "application/json",
                "Authorization": "Bearer " + localStorage.getItem('token')
            })
        };

헤더 부분 참조- "Authorization": "Bearer " + localStorage.getItem('token')


I replaced NSWag with Swashbuckle and didn't have any further issues.Swashbuckle은 typescript 파일을 생성하는 기능이 있습니까, 아니면 직접 추가 한 것이 있습니까?
호감

@crush swashbucle은 nuget nswag 라이브러리와 같은 json을 제공하는 백엔드 라이브러리입니다. 타이프 스크립트 파일을 생성하려면 npm의 nswag 패키지를 계속 사용해야합니다.
Alex Herman

맞아, 나는 이미 언젠가 내 프로젝트에 swashbuckle을 가지고 있는데 nswag 대신 TypeScript 모델을 생성 할 수 있다고 제안하는 것처럼 들렸다. 나는 nswag의 팬이 아닙니다 ... 무거워요. Swashbuckle에 연결된 자체 C #-> TypeScript 변환을 만들었습니다. 파일을 빌드 후 프로세스로 생성하고 프로젝트의 npm 피드에 게시합니다. 나는 이미 같은 일을하고있는 Swashbuckle 프로젝트를 간과하지 않도록하고 싶었습니다.
호감

8

다음은 ASP.NET Core Web API에서 JWT 토큰을 사용하는 클레임 ​​기반 인증의 매우 최소화 된 보안 구현입니다.

우선, 클레임이 사용자에게 할당 된 JWT 토큰을 반환하는 엔드 포인트를 노출해야합니다.

 /// <summary>
        /// Login provides API to verify user and returns authentication token.
        /// API Path:  api/account/login
        /// </summary>
        /// <param name="paramUser">Username and Password</param>
        /// <returns>{Token: [Token] }</returns>
        [HttpPost("login")]
        [AllowAnonymous]
        public async Task<IActionResult> Login([FromBody] UserRequestVM paramUser, CancellationToken ct)
        {

            var result = await UserApplication.PasswordSignInAsync(paramUser.Email, paramUser.Password, false, lockoutOnFailure: false);

            if (result.Succeeded)
            {
                UserRequestVM request = new UserRequestVM();
                request.Email = paramUser.Email;


                ApplicationUser UserDetails = await this.GetUserByEmail(request);
                List<ApplicationClaim> UserClaims = await this.ClaimApplication.GetListByUser(UserDetails);

                var Claims = new ClaimsIdentity(new Claim[]
                                {
                                    new Claim(JwtRegisteredClaimNames.Sub, paramUser.Email.ToString()),
                                    new Claim(UserId, UserDetails.UserId.ToString())
                                });


                //Adding UserClaims to JWT claims
                foreach (var item in UserClaims)
                {
                    Claims.AddClaim(new Claim(item.ClaimCode, string.Empty));
                }

                var tokenHandler = new JwtSecurityTokenHandler();
                  // this information will be retrived from you Configuration
                //I have injected Configuration provider service into my controller
                var encryptionkey = Configuration["Jwt:Encryptionkey"];
                var key = Encoding.ASCII.GetBytes(encryptionkey);
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Issuer = Configuration["Jwt:Issuer"],
                    Subject = Claims,

                // this information will be retrived from you Configuration
                //I have injected Configuration provider service into my controller
                    Expires = DateTime.UtcNow.AddMinutes(Convert.ToDouble(Configuration["Jwt:ExpiryTimeInMinutes"])),

                    //algorithm to sign the token
                    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)

                };

                var token = tokenHandler.CreateToken(tokenDescriptor);
                var tokenString = tokenHandler.WriteToken(token);

                return Ok(new
                {
                    token = tokenString
                });
            }

            return BadRequest("Wrong Username or password");
        }

이제 다음 과 같이 startup.csConfigureServices 내부 의 서비스에 인증을 추가하여 JWT 인증을 기본 인증 서비스로 추가해야합니다.

services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
             .AddJwtBearer(cfg =>
             {
                 cfg.RequireHttpsMetadata = false;
                 cfg.SaveToken = true;
                 cfg.TokenValidationParameters = new TokenValidationParameters()
                 {
                     //ValidateIssuerSigningKey = true,
                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Encryptionkey"])),
                     ValidateAudience = false,
                     ValidateLifetime = true,
                     ValidIssuer = configuration["Jwt:Issuer"],
                     //ValidAudience = Configuration["Jwt:Audience"],
                     //IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:Key"])),
                 };
             });

이제 다음과 같이 인증 서비스에 정책을 추가 할 수 있습니다.

services.AddAuthorization(options =>
            {
                options.AddPolicy("YourPolicyNameHere",
                                policy => policy.RequireClaim("YourClaimNameHere"));
            });

양자 택일로 , 당신은 또한 수 (필요 없음) 이것은 단지 응용 프로그램 시작시 한 번 실행으로 데이터베이스에서 귀하의 주장을 모두 채우고이 같은 정책에 추가 :

  services.AddAuthorization(async options =>
            {
                var ClaimList = await claimApplication.GetList(applicationClaim);
                foreach (var item in ClaimList)
                {                        
                    options.AddPolicy(item.ClaimCode, policy => policy.RequireClaim(item.ClaimCode));                       
                }
            });

이제 다음과 같이 권한을 부여 할 방법에 정책 필터를 배치 할 수 있습니다.

 [HttpPost("update")]
        [Authorize(Policy = "ACC_UP")]
        public async Task<IActionResult> Update([FromBody] UserRequestVM requestVm, CancellationToken ct)
        {
//your logic goes here
}

도움이 되었기를 바랍니다


3

JWT 토큰을 지원하기 위해 일부 타사 서버를 사용해야한다고 생각하며 WEB API 2에서는 기본 JWT 지원이 없습니다.

그러나 일부 형식의 서명 된 토큰 (JWT 아님)을 지원하기위한 OWIN 프로젝트가 있습니다. 웹 사이트에 대한 간단한 인증 형식 만 제공하기 위해 축소 된 OAuth 프로토콜로 작동합니다.

자세한 내용은 여기를 참조하십시오 .

다소 길지만 대부분의 부분은 컨트롤러와 ASP.NET Identity의 세부 사항이므로 전혀 필요하지 않습니다. 가장 중요한 것은

9 단계 : OAuth 베어러 토큰 생성 지원 추가

12 단계 : 백엔드 API 테스트

여기에서 프론트 엔드에서 액세스 할 수있는 엔드 포인트 (예 : "/ 토큰")를 설정하는 방법 (및 요청 형식에 대한 세부 사항)을 읽을 수 있습니다.

다른 단계는 해당 엔드 포인트를 데이터베이스 등에 연결하는 방법에 대한 세부 사항을 제공하며 필요한 부분을 선택할 수 있습니다.


2

필자의 경우 JWT는 별도의 API로 작성되므로 ASP.NET은 해독하고 유효성 검사 만하면됩니다. 허용되는 답변과 달리 비대칭 알고리즘 인 RSA를 사용하고 있으므로 SymmetricSecurityKey위에서 언급 한 클래스는 작동하지 않습니다.

결과는 다음과 같습니다.

using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Threading;
using System.Threading.Tasks;

    public static async Task<JwtSecurityToken> VerifyAndDecodeJwt(string accessToken)
    {
        try
        {
            var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{securityApiOrigin}/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
            var openIdConfig = await configurationManager.GetConfigurationAsync(CancellationToken.None);
            var validationParameters = new TokenValidationParameters()
            {
                ValidateLifetime = true,
                ValidateAudience = false,
                ValidateIssuer = false,
                RequireSignedTokens = true,
                IssuerSigningKeys = openIdConfig.SigningKeys,
            };
            new JwtSecurityTokenHandler().ValidateToken(accessToken, validationParameters, out var validToken);
            // threw on invalid, so...
            return validToken as JwtSecurityToken;
        }
        catch (Exception ex)
        {
            logger.Info(ex.Message);
            return null;
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.