Spring Security + JWT를 이용한 회원가입 + 로그인 #2

Woongbin·2023년 1월 4일
0
post-thumbnail

로그인

SecurityConfig

@RequiredArgsConstructor
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors().disable() // cors 허용 금지
                .csrf().disable() // csrf 허용 금지
                .formLogin().disable() // 폼기반 로그인 인증 허용
                .httpBasic().disable() // http 기반 인증 허용
                // 세션을 사용하지 않게 설정.
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests() // 요청에 의한 사용권환 체크
                .antMatchers("/user/login").permitAll() // permitAll() : 인증 없이 허용.
                .antMatchers("/user/join").permitAll()
                .antMatchers("/user").hasRole("USER")
                .anyRequest().authenticated();
    }
}
  • antMatchers : 해당 URL로 요청 시 설정을 해준다.
  • permitAll : antMatchers 설정한 접근을 권환에 상관없이 허용한다.
  • anyRequest() : 모든 요청에 대해 인증을 하게 설정한다.
  • hasRole("USER") : 유저의 권한을 가지고 있는 사람만 접근이 가능하다.

JwtProvider

/**
 * 토큰 생성 및 검증 클래스
 */
@RequiredArgsConstructor
@Component
public class JwtProvider {

    private String secretKey = "c2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQK";

    // 토큰 유효시간 30분
    private Long tokenValueTime = 30 * 60 * 1000L;

    private final UserDetailsService userDetailsService;

    // 객체 초기화, sercetKey를 Base64로 인코딩.
    @PostConstruct
    protected void init() {
        secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
    }

    // JWT 토큰 생성
    public String createToken(String userPK, List<String> roles) {
        Claims claims = Jwts.claims().setSubject(userPK); // JWT payload에 저장되는 정보단위
        claims.put("roles", roles);
        Date now = new Date(); // 날짜
        return Jwts.builder()
                .setClaims(claims) // 정보 저장.
                .setIssuedAt(now) // 토큰 발행 시간 저장.
                .setExpiration(new Date(now.getTime() + tokenValueTime)) // 현재 시간 더하기 30분
                .signWith(SignatureAlgorithm.HS256, secretKey) // 사용할 암호화 알고리즘(HS256)
                .compact();
    }

    // JWT 토큰에서 인증 정보 조회
    public Authentication getAuthentication(String token) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(this.getUserPk(token));
        return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
    }

    // 토큰에서 회원 정보 추출
    public String getUserPk(String token) {
        return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
    }

    // request의 Header에서 token값을 가져온다. "X-AUTH-TOKEN" : "TOKEN값"
    public String resolveToken(HttpServletRequest request) {
        return request.getHeader("X-AUTH-TOKEN");
    }

    // 토큰의 유효성 검사 + 만료일 확인
    public boolean validateToken(String jwtToken) {
        try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
            return !claims.getBody().getExpiration().before(new Date());
        } catch (Exception e) {
            return false;
        }
    }
}

JwtAuthenticationFilter

/**
 * JwtTokenProvider가 검증을 끝낸 Jwt로부터 유저 정보를 조회해서
 * UserPasswordAuthenticationFilter로  전달.
 */
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtProvider jwtProvider;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // Header에서 Jwt를 받아옴.
        String token = jwtProvider.resolveToken(request);

        // 유효한 토큰인지 확인.
        if (token != null && jwtProvider.validateToken(token)) {
            // 토큰으로부터 유저 정보를 가져 옴.
            Authentication authentication = jwtProvider.getAuthentication(token);

            // SecurityContext에 authentication 객체 저장
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }
}

UserService

private final JwtProvider jwtProvider;

@Transactional
    public String login(Map<String, String> users) {

        User user = userRepository.findByEmail(users.get("email"))
                .orElseThrow(() -> new IllegalArgumentException("가입되지 않은 이메일입니다."));

        String password = users.get("password");
        if (passwordEncoder.encode(user.getPassword()).equals(password)) {
            throw new IllegalArgumentException("잘못된 비밀번호입니다.");
        }

        List<String> roles = new ArrayList<>();
        roles.add(user.getRole().name());

        return jwtProvider.createToken(user.getNickname(), roles);
    }

이전에 작성한 UserSerivce 클래스에 로그인 코드를 작성한다.


UserController

@PostMapping("/login")
    public String login(@RequestBody Map<String, String> user) {
        return userService.login(user);
    }

테스트

회원가입


로그인

0개의 댓글