์ถ์ฒ: https://youtu.be/mgeuh8k3I4g
๊ทธ๋์ TIM Corey ์ ์๋์ ๊ฐ์ข๋ฅผ clone ํ๋ค๊ฐ ๋ค๋ฅธ๋ถ๋ ํด๋ด ๋๋ค.
Nick Chapsas ์ ์ธ์ฆ ,ํ๊ฐ์ ๊ดํ ๊ฐ์ข์ ๋๋ค.
์ ๊ฐ ์์ผ๋ก ๊ถํ ,์ธ์ฆ์ ๊ด๋ จ ์ ๋ฌด(?)๋ฅผ ํ ๊ฒ ๊ฐ์ ๊ณต๋ถ์ค์ด๊ธฐ๋ ํ๊ณ ์
chater 1
jwt ์ค๋ช
์ถ์ฒ: https://youtu.be/qDJYgGzmalQ
๋ณดํต ์ฌ์ฉ์๊ฐ ์น์ฌ์ดํธ์ ์ ๊ทผํ ๋ ์ฌ์ฉํ๊ฐ๋ฅผ ๋ฐ์์ผ ํฉ๋๋ค.
๊ณผ๊ฑฐ ๋ชจ๋ ธ๋กคํฑ ๊ฐ๋ฐ์์ ์ธ์ฆ์ ํต๊ณผํ ์ฌ์ฉ์๋ ์๋ณ๊ฐ์ ๋ณดํต ์๋ฐ๊ฐ ์ธ์ ์ ์ ์ฅํ๋๊ฒ์ด ๋ณดํต์ด์์ต๋๋ค.
์ด๋ ์ฌ์ฉ์๋ ์๋ฒ์๊ฒ ์์ฒญ์ ๋ณด๋ผ๋ ์์์ ๊ตฌ๋ถํ๋ Key๊ฐ ์๋๋ฐ ๋ณดํต
cookie ๊ฐ์ ์ฌ์ฉํฉ๋๋ค. ์ฌ์ฉ์์ cookie๋ฅผ ์๋ฒ ์ธ์
ํค๊ฐ๊ณผ ๋งค์นญํด์
์ฌ์ฉ์๋ฅผ ์๋ณํฉ๋๋ค. ์ ํต์ ์ธ ์ธ์ฆ ๋ฐฉ์์
๋๋ค.
ํ์ง๋ง ์น์ฌ์ดํธ๊ฐ ํ์ฅ์ ํ๋ค๊ณ ํ์๋ ์ด ์ธ์
์ ๊ณต์ ๋๊ธฐ ์ด๋ ต์ต๋๋ค.
(์ฑ๋ฅ๋ ์์ข๊ณ ์)
์ด ๋ฌธ์ ๋ฅผํด๊ฒฐํ๊ธฐ ์ํด stateless ๋ก ์๋ฒ์์ ์ฌ์ฉ์ ์ํ๊ฐ์ ๋ฐ๋ก ์ ์ฅํ์ง ์๊ณ
ํด์ฌ๊ฐ์ผ๋ก ์ฌ์ฉ์๋ฅผ ์ฒดํฌํ๋ ๋ฐฉ์์ ๊ฐ๋ฐํฉ๋๋ค.
์ด๊ฑด ํด๋น ์๋ฒ์์๋ง ์ฌ์ฉ๊ฐ๋ฅํ ์ด์ ๋ฅผ ์ฌ์ฉ์๊ฐ ๊ฐ์ง๊ณ ๋ค๋๋ค๋ ์๋ฏธ์ฃ
์ด๋ฐ ์์คํ ์ ์ฃผ๋ก API๋ก ๋ฌถ์ธ MSA์ ๋ง์ด ์ฌ์ฉํฉ๋๋ค.
์ฌ์ฉ์๋ ์ฌ์ดํธ๊ฐ ํ๋๊ฐ์ด ๋ณด์ด์ง๋ง ์ค์ ๋ก๋ ๋ฌผ๋ฆฌ์ ์ผ๋ก ํธ๋ํฝ์ ๋ถ์ฐ์ํต๋๋ค.
์ด๋ API๋ ์ฌ์ฉ์๋ฅผ ์๋ณํ๊ธฐ ์ํด ์์ฒญ Header ์ jwt token์ ๋ณด๋ด์ค๋๋ค.
JWT ํ ํฐ์ ๊ตฌ์กฐ
Header
typ: ํ ํฐ์ ํ์ ์ ์ง์ ํฉ๋๋ค. ๋ฐ๋ก JWT ์ด์ฃ .
alg: ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ ์ง์ ํฉ๋๋ค. ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก๋ ๋ณดํต HMAC SHA256 ํน์ RSA ๊ฐ ์ฌ์ฉ๋๋ฉฐ, ์ด ์๊ณ ๋ฆฌ์ฆ์, ํ ํฐ์ ๊ฒ์ฆ ํ ๋ ์ฌ์ฉ๋๋ signature ๋ถ๋ถ์์ ์ฌ์ฉ๋ฉ๋๋ค.
์ ๋ณด(payload)
token์ ๋ด์ ์ ๋ณด
{
โissโ: โvelopert.comโ,
โexpโ: โ1485270000000โ,
โhttps://velopert.com/jwt_claims/is_adminโ: true,
โuserIdโ: โ11028373727102โ,
โusernameโ: โvelopertโ
}
์๋ช
JSON Web Token ์ ๋ง์ง๋ง ๋ถ๋ถ์ ๋ฐ๋ก ์๋ช (signature) ์ ๋๋ค. ์ด ์๋ช ์ ํค๋์ ์ธ์ฝ๋ฉ๊ฐ๊ณผ, ์ ๋ณด์ ์ธ์ฝ๋ฉ๊ฐ์ ํฉ์นํ ์ฃผ์ด์ง ๋น๋ฐํค๋ก ํด์ฌ๋ฅผ ํ์ฌ ์์ฑํฉ๋๋ค
๊ตฌํ
API ํ๋ก์ ํธ๋ฅผ ์์ฑํฉ๋๋ค.
๊ท์ฐฎ์ผ๋ ๊ธฐ๋ณธ ์๊พธ๋ ๋ง๋ค์๊ณ ์ ^^
๊ทธ ๋ค์ nuget package
Microsoft.AspNetCore.Authentication.JwtBearer
๋ฅผ ์ค์นํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ program.cs ์์
builder.Services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
});
์๋น์ค๋ฅผ ์ถ๊ฐํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ jwt ๊ธฐ๋ณธ ์ต์
์ค์ ๊ฐ์ appsettings.json์ ์ ์ฅํฉ๋๋ค.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"JwtSettings": {
"Issuer": "https://dotnetdeve.com",
"Audience": "https://dotnetdeve.com/bluebird",
"Key": "dotnetdevforeverdotnetdevforeverdotnetdevforeverdotnetdevforeverdotnetdevforever"
}
}
์ถ๊ฐ๋ก ์๊น ๋ฑ๋กํ jwt ์ธ์ฆ์
builder.Services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x=> {
x.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = config["JwtSettings:Issuer"],
ValidAudience = config["JwtSettings:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["JwtSettings:Key"]!)),
ValidateIssuer = true,
ValidateAudience= true,
ValidateLifetime = true,
ValidateIssuerSigningKey =true
};
});
Token ์ ๋ํ ์ธ์ฆ ์ต์
์ ์ฝ์
ํฉ๋๋ค.
ValidIssuer,ValidAudience,IssuerSigningKey ๋ ์ด๊ฐ์ด ์ฌ๊ธฐ์ ์ฌ์ฉ๋๋ ๊ฐ์ด๋ผ๋ ์๋ฏธ์ด๊ณ ValidateIssuer,ValidateAudience,ValidateLifetime,ValidateIssuerSigningKey
ํ์ ์ฌ๋ถ์
๋๋ค.
์ฌ๋ด์ผ๋ก ์ด ์์ ์จ ๋ง ์ง์ง ๋น ๋ฅด๋ค์ 10๋ถ์ง๋ฆฌ ๊ฐ์์ธ๋ฐ ๋ถ๋์ ํ 30๋ถ ๋๋๊ฒ ๊ฐ๋ค์
๊ทธ๋ฆฌ๊ณ builder.Services.AddAuthentication(); ์ธ์ฆ์๋น์ค๋ฅผ ์ถ๊ฐํฉ๋๋ค.
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
๋ฏธ๋ค์จ์ด๋ ์ถ๊ฐํฉ๋๋ค. (์์ ์ค์!)
๊ทธ๋ฆฌ๊ณ controller ์ ๊ถํ ์์ฑ์ ์ถ๊ฐํฉ๋๋ค.
[ApiController]
[Route("[controller]")]
[Authorize]
public class WeatherForecastController : ControllerBase
์ด๋ฒ์๋ token ์ ์์ฑํ๋ conroller ๋ฅผ ์ถ๊ฐํ๊ฒ ์ต๋๋ค.
[HttpGet]
[Route("Token")]
public IActionResult GenerateToken()
{
var tokenhandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes(TokenSecret);
var timespan = TimeSpan.FromHours(8);
var claims = new List<Claim>
{
new (JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()),
new (JwtRegisteredClaimNames.Sub,"dotnetdev"),
new (JwtRegisteredClaimNames.Email,"dot@korea.com"),
new ("Userid","blueBird"),
};
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.Add(timespan),
Issuer = "https://dotnetdeve.com",
Audience = "https://dotnetdeve.com/bluebird",
SigningCredentials =new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256)
};
var token = tokenhandler.CreateToken(tokenDescriptor);
var jwt = tokenhandler.WriteToken(token);
return Ok(jwt);
}
์๋ ์ด๋ ๊ฒ ๊ฐ๋จํ๊ฒ ํ๋ฉด ์๋์ง๋ง ๊ตฌํ์๋ง ์ด์ ์ ๋ง์ถฐ์ ์ฌํํ๊ฒ ํ์ต๋๋ค.
swagger๋ก ํ์ธํด๋ณด๋ ์๋์ค๋๊ตฐ์ ๋์จ ํ ํฐ์ https://jwt.ms/
์ฌ๊ธฐ์์ ํ์ธํด๋ด
๋๋ค.
์ด์ ์ด token ์ด ์ด API ์์๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํ์ง ์ฌ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
Insomnia(https://insomnia.rest/) ๋ก ํ์ธํด๋ด ๋๋ค.
header ์ Authorization๋ฅผ ์ถ๊ฐํ๊ณ Bearer [token] ํฌํจํฉ๋๋ค.
์ญ์ ์๋์ค๋ค์
์ ์ฑ ์ค์
roll ๋ช ์ ์ ์ฅํ IdentityData.cs ์์ฑํํ
public class IdentityData
{
public const string AdminUserClaimName = "admin";
public const string AdminUserPolicyName = "Admin";
}
Program.cs์์ ์ ์ฑ ์ ๋ฑ๋กํฉ๋๋ค.
builder.Services.AddAuthorization(option =>
{
option.AddPolicy(IdentityData.AdminUserClaimName, p => p.RequireClaim(IdentityData.AdminUserClaimName,"true"));
});
token ์ IdentityData.AdminUserClaimName ์ด claim value๊ฐ true ์ฌ์ผ ํต๊ณผํ๋ค๋ ์๋ฏธ์ ๋๋ค.
์ด์ ์ด ์ ์ฑ ์ ์ฐ๋ API๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
[HttpGet("Test1")]
[Authorize(Policy =IdentityData.AdminUserPolicyName)]
public string GetAutor()
{
return "์๋
";
}
[Authorize(Policy =IdentityData.AdminUserPolicyName)]
์ด Claim์ด ํฌํจ๋์ผ ํต๊ณผ ๋๋ค ์๋ฏธ์
๋๋ค.
๊ทธ๋ฆฌ๊ณ token ์์ฑ์์
var claims = new List<Claim>
{
new (JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()),
new (JwtRegisteredClaimNames.Sub,"dotnetdev"),
new (JwtRegisteredClaimNames.Email,"dot@korea.com"),
new ("Userid","blueBird"),
new ("admin","true"),
};
์ด๋ ๊ฒ new (โadminโ,โtrueโ) claim์ ์ถ๊ฐํฉ๋๋ค.
์ด๋ ๊ฒ ์ ์๋๋๋ ๋ชจ์ต์ ๋ณผ์ ์์ต๋๋ค.
Git Source : GitHub - BlueBirdJun/JwtAuth_Tutorial
์ด๋ ๊ฒ API ์ ์ธ์ฆ ๊ถํ์ ๊ฐ์ข๋ฅผ ์ต๋ํ Simple ํ๊ฒ ์์ฑํด๋ณด์์ต๋๋ค.
๊ทธ๋์ ์ ๋ฆฌ๊ฐ ์๋์ ํ๋ค์๋๋ฐ ์ ๋ ์ฐธ ๋ป๊น์ ์๊ฐ์ด์์ต๋๋ค.
์์ผ๋ก๋ nick ์์ ์จ ๊ฐ์ข๋ฅผ ์์ฃผ๋ก ๋ณผ์๊ฐ์ ๋๋ค.