Skip to content

Usage_JWT

Junil Um edited this page Oct 16, 2018 · 1 revision

JWT 인증

JWT(Json Web Tokens) 을 이용하여 엑세스 토큰(Access Token)을 발급하고 인증 하는 방법입니다.

1. JWT 구성하기

JWT 를 구성하기 위해 Startup.cs 파일에 아래의 코드를 추가합니다. 그리고 appsettings.json 파일에 설정 정보를 설정합니다.

appsettings.json 파일에 설정 정보를 설정합니다.

{
  "authentication": {
    "key": "VERY_VERY_SECURE_KEY",
    "issuer": "http://localhost:12345"
  }
}

Startup.cs 파일에 아래의 코드를 추가하여 JWT 인증을 활성화 합니다.

ConfigureServices 메서드에 아래의 코드를 추가하여 JWT 에서 토큰 유효성 검사를 위한 매개변수를 서비스에 등록 합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvcWithWebSocketIo();

    var jwtTokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = _configuration["authentication:issuer"],
        ValidAudience = _configuration["authentication:issuer"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["authentication:key"]))
    };

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearerWithWebSocketIo(options =>
        {
            options.TokenValidationParameters = jwtTokenValidationParameters;
        });
}

등록된 서비스를 사용하기 위해 Configure 메서드에서 아래의 코드를 추가하여, 웻소켓과 인증 미들웨어를 활성화 합니다.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseWebSockets()
        .UseWebSocketIo()
        .UseAuthentication()
        .UseMvc();
}

2. JwtController 파일

JwtController.cs 컨트롤러 파일을 생성한 후, WebSocketIoController 를 상속합니다.

Authorize 특성을 컨트롤러에 선언하였으며, AuthenticationSchemes 매개변수를 이용하여 웹을 통한 JWT 인증과 웹소켓을 이용한 JWT 인증 모두를 활성화 합니다.

[Route("/api/jwt")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme + "," + WebSocketIoDefaults.AuthenticationScheme)]
public class JwtController : WebSocketIoController
{
    private readonly IWebSocketIo _webSocketIo;
    private readonly IConfiguration _configuration;

    public JwtController(IWebSocketIo webSocketIo,
        IConfiguration configuration) : base(webSocketIo)
    {
        _webSocketIo = webSocketIo;
        _configuration = configuration;
    }
}

이제 JWT 를 발급하는 Login 메서드와 인증된 사용자만 호출이 가능한 Me 메서드를 만듭니다.

[Route("login")]
[AllowAnonymous]
public IActionResult Login(LoginModel model)
{
    return Ok(new
    {
        AccessToken = BuildToken()
    });
}

[Route("me")]
public IActionResult Me()
{
    return Ok(new
    {
        Name = User.FindFirstValue(ClaimTypes.NameIdentifier),
        Email = User.FindFirstValue(ClaimTypes.Email)
    });
}

private string BuildToken()
{
    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.NameIdentifier, "admin"),
        new Claim(JwtRegisteredClaimNames.Email, "[email protected]"),
    };

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["authentication:key"]));
    var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

    var token = new JwtSecurityToken(_configuration["authentication:issuer"],
        _configuration["authentication:issuer"],
        claims: claims,
        expires: DateTime.Now.AddYears(1),
        signingCredentials: credentials);

    return new JwtSecurityTokenHandler().WriteToken(token);
}

3. 웹을 통한 인증

아래의 bash 스크립트를 실행하여 Access Token 을 발급 받습니다.

curl http://localhost:12345/api/jwt/login

위의 명령을 실행하면 아래와 같이 JSON 결과를 반환하며, accessToken 의 값은 매번 바뀔 수 있습니다.

{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBudHJlZXYuY29tIiwiZXhwIjoxNTcwNzc1NDQwLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQ1IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDoxMjM0NSJ9._rq2NHxnmtYGYOVjYV8j8xAZVWbjcaRnH3t429vKVd0"}

발급받은 Access Token 을 이용하여 내 정보를 조회하는 me API 를 호출합니다. 아래의 Authorization: Bearer 이후의 값은 발급받은 Access Token 값 입니다.

curl http://localhost:12345/api/jwt/me -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBudHJlZXYuY29tIiwiZXhwIjoxNTcwNzc1NDQwLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQ1IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDoxMjM0NSJ9._rq2NHxnmtYGYOVjYV8j8xAZVWbjcaRnH3t429vKVd0'

위 명령을 실행하면 아래와 같이 내 정보를 반환하여 표시합니다.

{
    "name":"admin",
    "email":"[email protected]"
}

4. 웹소켓을 이용한 인증

자바스크립트 또는 노드(Node) 환경에서 테스트해 볼 수 있지만, 간단하게 웹 브라우저의 개발자 도구를 이용하여 웹소켓 테스트를 합니다.

먼저 크롬(또는 개발자 도구를 지원하는 웹 브라우저) 브라우저를 실행하고, F12 키 또는 브라우저의 메뉴에서 '개발자 도구'를 실행합니다. 그리고 아래의 자바스크립트를 복사하여 붙여 넣습니다. (단, 새 탭을 열어 완전히 비어있는 탭이어야 합니다.)

먼저 웹소켓 객체를 생성한 후, 소켓이 서버와 연결이 되면 /api/jwt/login 을 호출하고 그 결과를 콘솔에 표시합니다.

var socket = new WebSocket('ws://localhost:12345');
socket.onopen = function() { socket.send(JSON.stringify({ path: '/api/jwt/login' })); }
socket.onmessage = function(event) { console.log(event.data); }

위 명령을 실행하면 아래와 같은 JSON 결과가 콘솔에 표시됩니다.

{
    "id":null,
    "emitName":null,
    "type":0,
    "statusCode":200,
    "data":{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBudHJlZXYuY29tIiwiZXhwIjoxNTcwNzc2NDM3LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQ1IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDoxMjM0NSJ9.g8iX7yJHYuDXHYjuCibHLkBXiGN81xv1Ny-qGYfPvA4"}
}

위 결과의 accessToken 값을 이용하여 내 정보를 반환하는 me API 를 호출합니다.

socket.send(JSON.stringify({ path: '/api/jwt/me', headers: { 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBudHJlZXYuY29tIiwiZXhwIjoxNTcwNzc2NDM3LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQ1IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDoxMjM0NSJ9.g8iX7yJHYuDXHYjuCibHLkBXiGN81xv1Ny-qGYfPvA4' }}));

위 명령을 실행하면 아래와 같이 내 정보를 반환하여 콘솔에 표시합니다.

{
    "id":null,
    "emitName":null,
    "type":0,
    "statusCode":200,
    "data":{
        "name":"admin",
        "email":"[email protected]"
    }
}