Spring Security/security
[SpringBoot + Security + JWT + JPA ] 회원가입 , 로그인 구현하기-3
데이25
2023. 2. 1. 19:43
이번 포스트 에서는 jwt 토큰을 발행해보고 인증하는 로직을 구현해겠다.
먼저 Application.java 에 비밀번호 암호화해줄 빈을 등록한다.
Application.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
config 패키지 밑에 jwt 패키지를 생성한다.
그리고 하위에 JwtProperties , JwtTokenProvider , JwtAuthFilter 클래스를 생성한다.
JwtProperties.java
public interface JwtProperties {
String SECRET = "your secret key";
int EXPIRATION_TIME = 864000000; // 10일 (1/1000초)
String HEADER_STRING = "Authorization";
}
JwtTokenProvider.java
@RequiredArgsConstructor
@Component
public class JwtTokenProvider {
private final UserDetailsService userDetailsService;
private String secretKey = Base64.getEncoder().encodeToString(JwtProperties.SECRET.getBytes());
public String generateToken(String userPk, String roles) {
Claims claims = Jwts.claims().setSubject(userPk);
claims.put("roles", roles);
Date now = new Date();
String jwtToken = Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + JwtProperties.EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, secretKey) // 사용할 암호화 알고리즘과 signature 에 들어갈 secret값 세팅
.compact();
System.out.println("jwt 토큰 : " + jwtToken);
return jwtToken;
}
public boolean verifyToken(String token) {
try {
Jws<Claims> claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token);
return claims.getBody()
.getExpiration()
.after(new Date());
} catch (Exception e) {
return false;
}
}
public String getUid(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
}
public Authentication getAuthentication(String token) {
UserDetails userDetails = userDetailsService.loadUserByUsername(this.getUid(token));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
}
generateToken 함수는 토큰을 발행하는 함수이다.
Claims 은 JWT의 Payload에 저장되는 정보 단위이고, 정보는 key value 쌍으로 저장된다.
JwtAuthFilter.java
@RequiredArgsConstructor
public class JwtAuthFilter extends GenericFilterBean {
private final JwtTokenProvider jwtTokenProvider;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String token = ((HttpServletRequest)request).getHeader(JwtProperties.HEADER_STRING);
if (token != null && jwtTokenProvider.verifyToken(token)) {
String email = jwtTokenProvider.getUid(token);
Authentication authentication = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
public Authentication getAuthentication(Member member) {
return new UsernamePasswordAuthenticationToken(member, "",
Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
}
}
doFilter에서 JwtProperties에서 정의해주었던 Authorization 헤더에 토큰을 가져오도록한다.
Filter를 다시 작성했으니 SecurityConfig를 수정하도록 한다.
SecurityConfig.java
@RequiredArgsConstructor
@Configuration
public class SecurityConfig {
//추가
private final JwtTokenProvider jwtTokenProvider;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf()
.ignoringAntMatchers("/h2-console/**")
.disable()
.headers().frameOptions().sameOrigin()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.formLogin().disable()
.httpBasic().disable()
.authorizeRequests()
.antMatchers("/join/**","/login/**","/index/**","/h2-console/**").permitAll()
.anyRequest().authenticated()
;
//추가
http.addFilterBefore(new JwtAuthFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}