ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JWT 실습 프로젝트 - 3 (로그인)
    SPRING/스프링 시큐리티 -JWT 2021. 9. 17. 20:01
    @RestController
    @RequestMapping("/api")
    public class AuthController {
        private final TokenProvider tokenProvider;
        private final AuthenticationManagerBuilder authenticationManagerBuilder;
    
        public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) {
            this.tokenProvider = tokenProvider;
            this.authenticationManagerBuilder = authenticationManagerBuilder;
        }
    
        @PostMapping("/authenticate")
        public ResponseEntity<TokenDto> authorize(@Valid @RequestBody LoginDto loginDto) {
    
            // 1. Login ID/PW 를 기반으로 AuthenticationToken 생성
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
    
            // 2. 실제로 검증 (사용자 비밀번호 체크) 이 이루어지는 부분
            //    authenticate 메서드가 실행이 될 때 CustomUserDetailsService 에서 만들었던 loadUserByUsername 메서드가 실행됨
            Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);
    
            // 3. 인증 정보를 기반으로 JWT 토큰 생성
            String jwt = tokenProvider.createToken(authentication);
    
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
    
            return new ResponseEntity<>(new TokenDto(jwt), httpHeaders, HttpStatus.OK);
        }
    }

    로그인 테스트

     

     

    Response Body의 헤더에도 정상적으로 생성된 토큰이 들어가 있는 것을 볼 수 있음. (Authorization 부분)

     

    POSTMAN의 TEST탭에서 위와 같이 코딩을 하면 POSTMAN 전역 변수에 해당 토큰을 담아서 다른 호출 작업에서 이 값을 이용할 수 있음.

     

    CustomUserDetailsService

    @Component("userDetailsService")
    public class CustomUserDetailsService implements UserDetailsService {
    
        private final UserRepository userRepository;
    
        public CustomUserDetailsService(UserRepository userRepository) {
            this.userRepository = userRepository;
        }
    
        @Override
        @Transactional
        public UserDetails loadUserByUsername(final String username) {
            return userRepository.findOneWithAuthoritiesByUsername(username)
                    .map(user -> createUser(username, user))
                    .orElseThrow(() -> new UsernameNotFoundException(username + " -> 데이터베이스에서 찾을 수 없습니다."));
        }
    
        private org.springframework.security.core.userdetails.User createUser(String username, User user) {
            if (!user.isActivated()) {
                throw new RuntimeException(username + " -> 활성화되어 있지 않습니다.");
            }
            List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
                    .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName()))
                    .collect(Collectors.toList());
            return new org.springframework.security.core.userdetails.User(user.getUsername(),
                    user.getPassword(),
                    grantedAuthorities);
        }
    }

    - UserDetailsService 인터페이스를 구현한 클래스.

    - loadUserByUsername 메소드를 오버라이드 하는데 여기서 넘겨받은 UserDetails  Authentication 의 패스워드를 비교하고 검증하는 로직을 처리.

    - DB 에서 username 을 기반으로 값을 가져오기 때문에 아이디 존재 여부도 자동으로 검증. 

Designed by Tistory.