용어 설명
JWT
(JSON Web Token)- JSON 형식 토큰의 표준 [RFC-7519]
- 장점: 권한 부여, 정보 교환시 유용
- 형식:
header
,payload
,signatrue
의 3가지로 구성되어 있다. 사이에 점을 추가해서header.payload.signature
로 표현된다.
const token = base64urlEncoding(header) + '.' + base64urlEncoding(payload) + '.' + base64urlEncoding(signature);
JWS
(JSON Web Signature)JSON Web Signature 를 의미한다.
[RFC-7515]JWT
와JWS
의 차이- JWT는 클레임 기반의 웹 토큰으로 사용자의 인증, 권한 부여와 같은 정보를 담을 수 있다.
- JWS는 JWT 유형 중 하나로 JWT를 생성하거나 사용되는 서명 매커니즘을 나타낸다. 즉, JWS는 JWT의 일부분으로 토큰의 신뢰성을 높이는 역할을 한다.
코드
JWT 생성
public void GenJWT() { // 1. HEADER RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048); RSAParameters privateKey = rsa.ExportParameters(true); var n = Base64UrlEncoder.Encode(privateKey.Modulus); var e = Base64UrlEncoder.Encode(privateKey.Exponent); var jsonWebKey = new JsonWebKey() { Kty = JsonWebAlgorithmsKeyTypes.RSA, N = n, E = e, }; var securityKey = new RsaSecurityKey(privateKey); var header = new JwtHeader(new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256)) { { "jwk", jsonWebKey } }; // 2. PAYLOAD // 2-1. Data 가져오기 UserInfo user = this.GetUserInfo(); // 2-2. 토큰 만료 시간 설정 DateTimeOffset currentDateTime = DateTimeOffset.Now; long nbf = currentDateTime.ToUnixTimeSeconds(); DateTimeOffset expirationDateTime = currentDateTime.AddHours(24); long exp = expirationDateTime.ToUnixTimeSeconds(); var payload = new JwtPayload() { { "iss", user.Company.Url }, { "sub", user.Name }, { "nbf", nbf }, { "exp", exp }, { "jti", user.Email }, { "user", user }, }; // 3. JWT 생성 var token = new JwtSecurityToken(header, payload); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.WriteToken(token); Console.WriteLine(jwtToken); }
- header
{ "alg": "RS256", "typ": "JWT", "jwk": { "e": "AQAB", "kty": "RSA", "n": "길어서 생략" } }
- payload
{ "iss": "https://solyi.kr", "sub": "솔이", "nbf": 1691566698, "exp": 1691653098, "jti": "solyi@naver.com", "user": { "Id": "solyi", "Password": "password", "Name": "솔이", "Birthday": "1991-05-15T00:00:00", "Mobile": "010-6666-7777", "Email": "solyi@solyi.com", "Company": { "Name": "trivue", "Address": "서울 양천구", "Url": "https://solyi.kr" } } }
- JWT
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6IlJTQSIsIm4iOiJyMzZGU1hvOTFjQTNwcGpjTHo5c0VIeDZ2UnV0bDRNZ2lLVHZERWNldGlWZ1FjanFCd2EwSFRrbzJ4amJVaWlLSVFYaEY0OGktS2VTbHluZVpUOTV2RkpEM2ZzZ1FvZU5kaEYxWVBZMmxtZ21FOEFJdFV0emktdWRLa3lBanB6X2RlZnBCaGhnOHN4WFdQVW9iU2ZEUFIzOElFZXJIckJLVXZGZGNqRG42aHhhLV9ERWd0QmxXdzR6NktkVXZqRGhibWoyUHNaRHNrME9ZVFBTdFdxcU5KSm5BSXR4NktHNXJTbDZtZFlETVg4NTdkYVZqVEt6UEJOUHhldDRvVk5SZWJxdG5YbXNfV0tYM1pHQlBHMEJTVkVKMEdCck56c3dsekV4TGJiVFdmV0RlV0c5U0RVQm5DeHRkZWlhcUVTRU5XU0ExVkF1QWt5WGtZSG14dHIwalEifX0.eyJpc3MiOiJodHRwczovL3NvbHlpLmtyIiwic3ViIjoi7IaU7J20IiwibmJmIjoxNjkxNTY3MDIyLCJleHAiOjE2OTE2NTM0MjIsImp0aSI6InNvbHlpQG5hdmVyLmNvbSIsInVzZXIiOnsiSWQiOiJzb2x5aSIsIlBhc3N3b3JkIjoicGFzc3dvcmQiLCJOYW1lIjoi7IaU7J20IiwiQmlydGhkYXkiOiIxOTkxLTA1LTE1VDAwOjAwOjAwIiwiTW9iaWxlIjoiMDEwLTY2NjYtNzc3NyIsIkVtYWlsIjoic29seWlAbmF2ZXIuY29tIiwiQ29tcGFueSI6eyJOYW1lIjoidHJpdnVlIiwiQWRkcmVzcyI6IuyEnOyauCDslpHsspzqtawiLCJVcmwiOiJodHRwczovL3NvbHlpLmtyIn19fQ.gI6QwifCtzTzRILZl04yqr7ONZb1qMOROnIArYjBHvlDHtoPbQqNhiQpDzub7UBzW92gJR3tq1FPonuTRy5QD7B-nbVvnsgIRvBpUzoc2nIk174VotZbgvM3QmgTE2FQ9yrnJNq6CHFiGdGRlSOWSZtgeat9ehYMKwHemxqg5d54pqmSpr1Y6lHo2tMeFJBDH4RZGYzNzGN8Px35U0S0vtQUmcgFRcMO5dLch2f7Q8FDejg9RoDUkMM83UifGNvXdNONwCKd2nSX1UCvocJfmPGaRDq7U9hYFu6C8c052IdVwgvFrownp_xnWwzeyaDXxSe8VIbF8GWMZfBBeHcJrA
- ↑ 이걸 복사해서 https://jwt.io 에 붙여넣기 하면
header
와payload
값이 짜잔
JWT 검증
public bool VerifyJWT_RS256_Signature(string jwt, string publicKey, string exponent) { var jwtArray = jwt.Split('.'); string publicKeyFixed = (publicKey.Length % 4 == 0 ? publicKey : publicKey + "====".Substring(publicKey.Length % 4)).Replace("_", "/").Replace("-", "+"); var publicKeyBytes = Convert.FromBase64String(publicKeyFixed); var jwtSignatureFixed = (jwtArray[2].Length % 4 == 0 ? jwtArray[2] : jwtArray[2] + "====".Substring(jwtArray[2].Length % 4)).Replace("_", "/").Replace("-", "+"); var jwtSignatureBytes = Convert.FromBase64String(jwtSignatureFixed); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters( new RSAParameters() { Modulus = publicKeyBytes, Exponent = Convert.FromBase64String(exponent) } ); SHA256 sha256 = SHA256.Create(); byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(jwtArray[0] + '.' + jwtArray[1])); RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa); rsaDeformatter.SetHashAlgorithm("SHA256"); if (rsaDeformatter.VerifySignature(hash, jwtSignatureBytes)) { return true; } else { return false; } }
반응형
'Backend > C# .NET' 카테고리의 다른 글
C#의 recode 레코드 왜 쓰나요? 샘플 코드 예제 / 명명 규칙 (0) | 2023.12.04 |
---|---|
CQRS 패턴을 적용한 MediatR과 FluentValidation (0) | 2023.11.28 |
Entity Framework Core 개념 / 장단점 / 코드 예제 / 사용 방법 / 데이터 가져오기, 수정, 삭제 / 샘플 코드 (0) | 2023.11.26 |
[ASP.NET] Entity Framework Core (0) | 2021.12.13 |
[ASP.NET] 개요 / MVC 패턴 / 의존성 주입 패턴 (0) | 2021.12.07 |