Asp Net Core 5 Rest API 및 JWT의 단계별 인증

32949 단어 jwtapibeginnersdotnet
본 문서에서 JWT 인증을 Asp에 추가하는 방법을 보여 드리겠습니다.Net Core REST API
저희가 토론할 몇 가지 주제는 등록, 로그인 기능, JWTs("Json 웹 영패") 사용과 신분 검증입니다.
유튜브에서도 완전한 단계별 영상을 볼 수 있다.
소스 코드를 다운로드하려면 다음과 같이 하십시오.
https://github.com/mohamadlawand087/v7-RestApiNetCoreAuthentication
API 개발 시리즈의 두 번째 섹션으로, 다음 링크를 통해 여러 섹션을 볼 수 있습니다.
  • 섹션 1:
  • 섹션 3:
  • 현재 작업은 이전 기사()에서 만든 이전 Todo REST 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 개발 시리즈의 두 번째 섹션으로, 다음 링크를 통해 여러 섹션을 볼 수 있습니다.
  • 섹션 1:
  • 섹션 3:
  • 좋은 웹페이지 즐겨찾기