[ASP.NET Core][Entity Framework Core] JWT 2 사용해보기
23627 단어 csharpaspnetcore
소개
이번에는 마지막 프로젝트의 세부 사항을 볼 것입니다.
JWT 소개
JWT(JSON Web Token)는 3개의 JSON 값으로 만들어집니다.
{Header}.{Payload}.{Signature}
해당 값은 Base64로 인코딩됩니다.
예를 들어 "헤더"에는 토큰 유형 이름과 알고리즘 이름이 있습니다.
(암호화 때문에 서명을 직접 복호화할 수 없음)
UserTokens.cs
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
namespace BookshelfSample.Users;
public class UserTokens: IUserTokens
{
...
public string GenerateToken(ApplicationUser user)
{
return new JwtSecurityTokenHandler()
.WriteToken(new JwtSecurityToken(this.config["Jwt:Issuer"],
this.config["Jwt:Audience"],
claims: new []
{
new Claim(ClaimTypes.Email, user.Email)
},
expires: DateTime.Now.AddSeconds(30),
signingCredentials: new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.config["Jwt:Key"])),
SecurityAlgorithms.HmacSha256)));
}
public IEnumerable<string> DecodeToken(string value)
{
foreach(var t in value.Split("."))
{
yield return Base64UrlEncoder.Decode(t);
}
}
}
ApplicationUserService.cs
...
public async Task<UserActionResult> SigninAsync(SigninValue value, ISession session)
{
var target = await this.users.GetByEmailForSigninAsync(value.Email);
if(target == null)
{
return ActionResultFactory.GetFailed("Invalid e-mail or password");
}
var result = await this.signInManager.PasswordSignInAsync(target, value.Password, false, false);
if(result.Succeeded)
{
var token = this.userTokens.GenerateToken(target);
session.SetString("user-token", token);
logger.LogDebug($"Token: {token}");
foreach(var t in this.userTokens.DecodeToken(token))
{
logger.LogDebug($"Decoded: {t}");
}
return ActionResultFactory.GetSucceeded();
}
return ActionResultFactory.GetFailed("Invalid e-mail or password");
}
...
결과
Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9lbWFpbGFkZHJlc3MiOiJleGFtcGxlQG1haWwuY29tIiwiZXhwIjoxNjQ4MzEzMDY0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUxMTAiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUxMTAifQ.AtzZ-RnSNG3SRLEsNEC3XI7OjiQ8Y8YWpRdBCTI5vNY
Decoded: {"alg":"HS256","typ":"JWT"}
Decoded: {"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress":"[email protected]","exp":1648397836,"iss":"http://localhost:5110","aud":"http://localhost:5110"}
Decoded: ♀?▼?Q? ←|?☻?L????YGn?Y~?$?1???
RFC7519에서 Header 및 Claims의 사양을 읽을 수 있습니다.
입증
JWT 전달자 인증을 위해 AuthenticationBuilder에 옵션과 함께 "AddJwtBearer"를 추가했습니다.
Program.cs
...
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
};
});
...
"Validate~"속성을 모두 "false"로 설정하면 항상 동일한 토큰 값을 사용할 수 있나요?
대답은 '예'입니다.
Program.cs
...
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateTokenReplay = false,
ValidateActor = false,
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = false,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
};
});
...
app.Use(async (context, next) =>
{
var token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9lbWFpbGFkZHJlc3MiOiJleGFtcGxlQG1haWwuY29tIiwiZXhwIjoxNjQ4MzEzMDY0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUxMTAiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUxMTAifQ.AtzZ-RnSNG3SRLEsNEC3XI7OjiQ8Y8YWpRdBCTI5vNY";
context.Request.Headers.Add("Authorization", $"Bearer {token}");
await next();
});
...
설정된 토큰은 보안 키로 암호화되므로 "IssuerSigningKey"를 생략할 수 없습니다.
쓰기 토큰
다음으로 JWT 생성을 살펴보겠습니다.
UserTokens.cs
...
public string GenerateToken(ApplicationUser user)
{
return new JwtSecurityTokenHandler()
.WriteToken(new JwtSecurityToken(this.config["Jwt:Issuer"],
this.config["Jwt:Audience"],
claims: new []
{
new Claim(ClaimTypes.Email, user.Email)
},
expires: DateTime.Now.AddSeconds(30),
signingCredentials: new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.config["Jwt:Key"])),
SecurityAlgorithms.HmacSha256)));
}
...
JwtSecurityToken에는 5개의 오버로드가 있습니다. 그러나 아무도 JwtHeader, JwtPayload 및 JwtSecurityToken을 인수로 사용하지 않습니다.
JwtSecurityToken.cs는 SigningCredentials에서 JwtHeader를 만들고 JwtSecurityToken 생성자의 다른 인수에서 JwtPayload를 만듭니다.
헤더 및 페이로드 섹션은 Base64로 인코딩된 JSON입니다.
그러나 서명 섹션은 여러 Base64 인코딩 값으로 만들어집니다.
그래서 직접 해독할 수 없습니다.
보안 키
보안 키에는 특별한 요구사항이 없습니다.
하지만 HMAC SHA256을 사용하기 때문에 키 값의 길이가 16비트 이상이어야 합니다.
키가 16비트 미만이면 런타임 예외가 발생합니다.
The encryption algorithm 'System.String' requires a key size of at least 'System.Int32' bits. Key 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey', is of size: 'System.Int32'. (Parameter 'key')
...
알파벳과 숫자 외에도 기호, 일본어 등을 사용할 수 있다.
키가 길든 짧든 결과는 256비트 길이입니다.
자원
Reference
이 문제에 관하여([ASP.NET Core][Entity Framework Core] JWT 2 사용해보기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/masanori_msl/aspnet-coreentity-framework-core-try-jwt-2-2iij텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)