Asp Net Core 5 Rest API 및 JWT의 단계별 인증
저희가 토론할 몇 가지 주제는 등록, 로그인 기능, JWTs("Json 웹 영패") 사용과 신분 검증입니다.
유튜브에서도 완전한 단계별 영상을 볼 수 있다.
소스 코드를 다운로드하려면 다음과 같이 하십시오.
https://github.com/mohamadlawand087/v7-RestApiNetCoreAuthentication
API 개발 시리즈의 두 번째 섹션으로, 다음 링크를 통해 여러 섹션을 볼 수 있습니다.
이 글을 읽는 동시에 저와 함께 프로그램을 구축할 수도 있고githubhttps://github.com/mohamadlawand087/v6-RestApiNetCore5에서 원본 코드를 얻을 수도 있습니다.
일단 우리의 코드가 준비되면, 우리는 시작합시다.
우선, 우리는 신분 검증을 사용하기 위해 몇 가지 소프트웨어 패키지를 설치해야 한다
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Identity.UI
그리고 우리가 해야 할 일은 응용 프로그램 설정을 업데이트하는 것이다.json, 저희 appsettings에 JWT 설정 부분을 추가해야 합니다. 이 설정에 JWT 기밀을 추가해야 합니다."JwtConfig": {
"Secret" : "ijurkbdlhmklqacwqzdxmkkhvqowlyqa"
},
우리의 비밀을 생성하기 위해서, 우리는 무료 웹 도구를 사용하여 무작위 32자 문자열 https://www.browserling.com/tools/random-string 을 생성할 것입니다.프로그램 설정에 무작위로 32자 문자열을 추가하면 루트 디렉터리에 configuration이라는 새 폴더를 만들어야 합니다.
이 구성 폴더에서 JwtConfig이라는 새 클래스를 만듭니다.
public class JwtConfig
{
public string Secret { get; set; }
}
현재 startup 클래스를 업데이트해야 합니다.Configure 서비스 방법에서 프로그램에 JwtConfiguration을 주입하기 위해 다음과 같은 내용을 추가해야 합니다.services.Configure<JwtConfig>(Configuration.GetSection("JwtConfig"));
이 설정을 startup 클래스에 추가하고 Asp.Net 코어 middlewear와 IOC 용기에 등록하십시오.다음 단계는 startup 클래스에 인증을 추가하고 설정하는 것입니다.Configure 서비스 방법에서 다음과 같은 내용을 추가해야 합니다
// within this section we are configuring the authentication and setting the default scheme
services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwt => {
var key = Encoding.ASCII .GetBytes(Configuration["JwtConfig:Secret"]);
jwt.SaveToken = true;
jwt.TokenValidationParameters = new TokenValidationParameters{
ValidateIssuerSigningKey= true, // this will validate the 3rd part of the jwt token using the secret that we added in the appsettings and verify we have generated the jwt token
IssuerSigningKey = new SymmetricSecurityKey(key), // Add the secret key to our Jwt encryption
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = false,
ValidateLifetime = true
};
});
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApiDbContext>();
Configure Services를 업데이트한 후 인증을 추가하여 Configure 메서드를 업데이트해야 합니다.app.UseAuthentication();
응용 프로그램 구축에 필요한 설정을 추가하면 모든 것이 제대로 구축되었는지 확인할 수 있습니다.dotnet run
dotnet build
다음 단계는 저희 ApiDbContext를 업데이트하는 것입니다. Asp.Net를 이용하여 저희가 제공한 신분 제공 프로그램을 이용하면 데이터 폴더에 있는 ApiDbContext로 이동하고 ApiDbContext 클래스를 업데이트합니다. 아래와 같습니다.public class ApiDbContext : IdentityDbContext
Identity DbContext 대신 Identity DbContext에서 계승함으로써 Entity Framework는 인증을 사용하고 있음을 알 수 있습니다. 기본 신분표를 사용하는 인프라를 구축할 것입니다.데이터베이스에 표지표를 생성하려면 스크립트를 이동하고 실행할 준비를 해야 합니다.터미널 내부에서 이 점을 실현하려면 다음과 같은 내용을 입력해야 한다
dotnet ef migrations add "Adding authentication to our Api"
dotnet ef database update
마이그레이션이 완료되면 데이터베이스 애플리케이션을 열 수 있습니다.실체 프레임워크가 우리를 위해 표지표를 만들었음을 알 수 있다다음 단계는 컨트롤러를 설정하고 사용자를 위한 등록 과정을 설정하는 것입니다.내부 및 외부 컨트롤러 폴더에는 디렉터와 DTO(데이터 전송 객체)가 필요합니다.
먼저 루트 디렉터리에 Domain이라는 새 폴더를 추가한 다음AuthResult라는 클래스를 추가합니다
public class AutResult
{
public string Token {get;set;}
public bool Result { get; set; }
public List<string> Errors { get; set; }
}
우선 일부 폴더를 추가하여 DTO를 구성하고 Models 폴더에 DTO라는 폴더를 추가하며 DTO 폴더에 두 개의 폴더 요청/응답을 생성합니다컨트롤러에 UserRegistrationRequestDto를 추가해야 하는 등록 작업에 사용됩니다.그리고Models/DTO/Requests로 이동하여 UserRegistrationRequestDto라는 새 클래스를 추가합니다
Models/Dto/Requests/UserRegistrationRequestDto.대테러 엘리트
// For simplicity we are only adding these 3 feilds we can change it and make it as complex as we need
public class UserRegistrationRequestDto
{
[Required]
public string Name { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
Model/Dto/Response/RegistrationResponse.대테러 엘리트// We are inheriting from AuthResult class
public class RegistrationResponse : AuthResult
{
}
현재 우리는 사용자 등록 컨트롤러를 추가하고 컨트롤러 폴더에 새로운 종류를 추가해야 한다. 우리는 AuthManagement Controller라고 부르며, 아래의 코드를 사용하여 업데이트한다[Route("api/[controller]")] // api/authmanagement
[ApiController]
public class AuthManagementController : ControllerBase
{
private readonly UserManager<IdentityUser> _userManager;
private readonly JwtConfig _jwtConfig;
public AuthManagementController(UserManager<IdentityUser> userManager, IOptionsMonitor<JwtConfig> optionsMonitor)
{
_userManager = userManager;
_jwtConfig = optionsMonitor.CurrentValue;
}
[HttpPost]
[Route("Register")]
public async Task<IActionResult> Register([FromBody] UserRegistrationRequestDto user)
{
// Check if the incoming request is valid
if(ModelState.IsValid)
{
// check i the user with the same email exist
var existingUser = await _userManager.FindByEmailAsync(user.Email);
if(existingUser != null)
{
return BadRequest(new RegistrationResponse() {
Result = false,
Errors = new List<string>(){
"Email already exist"
}});
}
var newUser = new IdentityUser(){Email = user.Email, UserName = user.Email};
var isCreated = await _userManager.CreateAsync(newUser, user.Password);
if(isCreated.Succeeded)
{
var jwtToken = GenerateJwtToken(newUser);
return Ok(new RegistrationResponse() {
Result = true,
Token = jwtToken
});
}
return new JsonResult(new RegistrationResponse(){
Result = false,
Errors = isCreated.Errors.Select(x => x.Description).ToList()}
) {StatusCode = 500};
}
return BadRequest(new RegistrationResponse() {
Result = false,
Errors = new List<string>(){
"Invalid payload"
}});
}
private string GenerateJwtToken(IdentityUser user)
{
// Now its ime to define the jwt token which will be responsible of creating our tokens
var jwtTokenHandler = new JwtSecurityTokenHandler();
// We get our secret from the appsettings
var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);
// we define our token descriptor
// We need to utilise claims which are properties in our token which gives information about the token
// which belong to the specific user who it belongs to
// so it could contain their id, name, email the good part is that these information
// are generated by our server and identity framework which is valid and trusted
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new []
{
new Claim("Id", user.Id),
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
// the JTI is used for our refresh token which we will be convering in the next video
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
// the life span of the token needs to be shorter and utilise refresh token to keep the user signedin
// but since this is a demo app we can extend it to fit our current need
Expires = DateTime.UtcNow.AddHours(6),
// here we are adding the encryption alogorithim information which will be used to decrypt our token
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
};
var token = jwtTokenHandler.CreateToken(tokenDescriptor);
var jwtToken = jwtTokenHandler.WriteToken(token);
return jwtToken;
}
}
등록 작업이 끝난 후, 우리는 지금postman에서 그것을 테스트하고, jwt 영패를 획득할 수 있습니다따라서 다음 단계에서 사용자 로그인 요청을 만들 것입니다.
public class UserLoginRequest
{
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
그런 다음 AuthManagement Controller에 로그인 작업을 추가해야 합니다.[HttpPost]
[Route("Login")]
public async Task<IActionResult> Login([FromBody] UserLoginRequest user)
{
if(ModelState.IsValid)
{
// check if the user with the same email exist
var existingUser = await _userManager.FindByEmailAsync(user.Email);
if(existingUser == null)
{
// We dont want to give to much information on why the request has failed for security reasons
return BadRequest(new RegistrationResponse() {
Result = false,
Errors = new List<string>(){
"Invalid authentication request"
}});
}
// Now we need to check if the user has inputed the right password
var isCorrect = await _userManager.CheckPasswordAsync(existingUser, user.Password);
if(isCorrect)
{
var jwtToken = GenerateJwtToken(existingUser);
return Ok(new RegistrationResponse() {
Result = true,
Token = jwtToken
});
}
else
{
// We dont want to give to much information on why the request has failed for security reasons
return BadRequest(new RegistrationResponse() {
Result = false,
Errors = new List<string>(){
"Invalid authentication request"
}});
}
}
return BadRequest(new RegistrationResponse() {
Result = false,
Errors = new List<string>(){
"Invalid payload"
}});
}
지금 우리는 그것을 테스트할 수 있다. 우리는 우리의 jwt 영패가 성공적으로 생성되었음을 볼 수 있다. 다음 단계는 우리의 컨트롤러를 보호하는 것이다. 이를 위해 우리가 해야 할 일은 컨트롤러에 authorize 속성을 추가하는 것이다.[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")] // api/todo
[ApiController]
public class TodoController : ControllerBase
현재, 만약 우리가 그것을 테스트한다면, 우리는 어떠한 요청도 실행할 수 없습니다. 왜냐하면 우리는 권한을 부여받지 않았기 때문입니다. 권한 수여 요청을 보내기 위해서, Asp.Net 이 그것을 검증하고, 우리가 실행할 수 있도록 영패를 탑재한 권한 수여 헤더를 추가해야 합니다.시간을 내서 본문을 읽어 주셔서 감사합니다
API 개발 시리즈의 두 번째 섹션으로, 다음 링크를 통해 여러 섹션을 볼 수 있습니다.
Reference
이 문제에 관하여(Asp Net Core 5 Rest API 및 JWT의 단계별 인증), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/moe23/asp-net-core-5-rest-api-authentication-with-jwt-step-by-step-140d텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)