■ JWT(Json Web Token) 인증을 사용하는 방법을 보여준다.
※ JWT 기본 개념을 이해하기 위한 소스 코드이다.
▶ ConstantHelper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
namespace TestProject { /// <summary> /// 상수 헬퍼 /// </summary> public class ConstantHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 발행자 /// </summary> public const string Issuer = "https://localhost:44306/"; /// <summary> /// 청중 /// </summary> public const string Audiance = "https://localhost:44306/"; /// <summary> /// 패스워드 /// </summary> public const string Password = "not_too_short_secret_otherwise_it_might_error"; #endregion } } |
※ Issuer, Audiance, Password 필드 값은 적절히 수정한다.
▶ Startup.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Tokens; using System.Text; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 시작 /// </summary> public class Startup { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 서비스 컬렉션 구성하기 - ConfigureServices(services) /// <summary> /// 서비스 컬렉션 구성하기 /// </summary> /// <param name="services">서비스 컬렉션</param> public void ConfigureServices(IServiceCollection services) { services.AddAuthentication("OAuth") .AddJwtBearer ( "OAuth", options => { byte[] passwordByteArray = Encoding.UTF8.GetBytes(ConstantHelper.Password); SymmetricSecurityKey key = new SymmetricSecurityKey(passwordByteArray); // GET 방식으로 access_token 값에 JWT를 전달할 수 있게 해준다. options.Events = new JwtBearerEvents() { OnMessageReceived = context => { if(context.Request.Query.ContainsKey("access_token")) { context.Token = context.Request.Query["access_token"]; } return Task.CompletedTask; } }; options.TokenValidationParameters = new TokenValidationParameters() { ValidIssuer = ConstantHelper.Issuer, ValidAudience = ConstantHelper.Audiance, IssuerSigningKey = key }; } ); services.AddControllersWithViews(); } #endregion #region 구성하기 - Configure(app, environment) /// <summary> /// 구성하기 /// </summary> /// <param name="app">애플리케이션 빌더</param> /// <param name="environment">웹 호스트 환경</param> public void Configure(IApplicationBuilder app, IWebHostEnvironment environment) { if(environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints ( endpoints => { endpoints.MapDefaultControllerRoute(); } ); } #endregion } } |
▶ Controllers/HomeController.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; namespace TestProject.Controllers { /// <summary> /// 홈 컨트롤러 /// </summary> public class HomeController : Controller { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 인덱스 페이지 처리하기 - Index() /// <summary> /// 인덱스 페이지 처리하기 /// </summary> /// <returns>액션 결과</returns> public IActionResult Index() { return View(); } #endregion #region 인증 페이지 처리하기 - Authenticate() /// <summary> /// 인증 페이지 처리하기 /// </summary> /// <returns>액션 결과</returns> public IActionResult Authenticate() { List<Claim> claimList = new List<Claim> { new Claim(JwtRegisteredClaimNames.Sub , "ID0001" ), new Claim(JwtRegisteredClaimNames.Birthdate, "2020-01-01" ), new Claim(JwtRegisteredClaimNames.Email , "test@daum.net"), new Claim(JwtRegisteredClaimNames.Gender , "Male" ) }; byte[] passwordByteArray = Encoding.UTF8.GetBytes(ConstantHelper.Password); SymmetricSecurityKey key = new SymmetricSecurityKey(passwordByteArray); string algorithm = SecurityAlgorithms.HmacSha256; SigningCredentials signingCredentials = new SigningCredentials(key, algorithm); JwtSecurityToken token = new JwtSecurityToken ( ConstantHelper.Issuer, ConstantHelper.Audiance, claimList, notBefore : DateTime.Now, expires : DateTime.Now.AddHours(1), signingCredentials ); string jwt = new JwtSecurityTokenHandler().WriteToken(token); return Ok(new { access_token = jwt }); } #endregion #region 비밀 페이지 처리하기 - Secret() /// <summary> /// 비밀 페이지 처리하기 /// </summary> /// <returns>액션 결과</returns> [Authorize] public IActionResult Secret() { return View(); } #endregion } } |
※ 테스트 방법
1. 웹 브라우저를 실행한다.
2. 웹 브라우저에서 아래 URL을 실행한다.
▶ URL
1 2 3 |
https://localhost:44306/home/authenticate |
※ 포트 번호는 상황에 맞게 수정한다.
3. 웹 브라우저에서 아래와 같이 결과가 출력된다.
▶ 출력 결과
1 2 3 |
{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJJRDAwMDEiLCJiaXJ0aGRhdGUiOiIyMDIwLTAxLTAxIiwiZW1haWwiOiJ0ZXN0QGRhdW0ubmV0IiwiZ2VuZGVyIjoiTWFsZSIsIm5iZiI6MTYwNDA4NTAwNCwiZXhwIjoxNjA0MDg4NjA0LCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDMwNi8iLCJhdWQiOiJodHRwczovL2xvY2FsaG9zdDo0NDMwNi8ifQ.u4u7smQfxaD0X1NWPkO6m75H0ooeBpFzL1imLn3gRnA"} |
4. 웹 브라우저에서 아래 URL을 실행한다.
▶ URL
1 2 3 |
https://localhost:44306/home/secret?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJJRDAwMDEiLCJiaXJ0aGRhdGUiOiIyMDIwLTAxLTAxIiwiZW1haWwiOiJ0ZXN0QGRhdW0ubmV0IiwiZ2VuZGVyIjoiTWFsZSIsIm5iZiI6MTYwNDA4NTAwNCwiZXhwIjoxNjA0MDg4NjA0LCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDMwNi8iLCJhdWQiOiJodHRwczovL2xvY2FsaG9zdDo0NDMwNi8ifQ.u4u7smQfxaD0X1NWPkO6m75H0ooeBpFzL1imLn3gRnA |
※ 포트 번호는 상황에 맞게 수정한다.