JWT(토큰 기반 인증)는 JSON Web Token의 약자로, 웹 표준인 RFC 7519에서 정의된 개방형 표준
- JSON 형식을 사용하여 정보를 안전하게 전달하기 위한 컴팩트하고 자가수용적인 방법을 제공
- 주로 인증 및 정보 교환에 사용되며, 클레임(claim) 기반으로 정보를 저장하고 전송
✔️ JWT 구성
Header(헤더): 토큰의 유형 및 해싱 알고리즘 등의 메타데이터를 포함
Payload(페이로드): 토큰에 포함될 클레임(사용자 정보, 권한 등)
Signature(서명): 헤더와 페이로드를 결합하고, 비밀 키를 사용하여 서명된 값으로, 토큰의 유효성 검증
user 객체 생성 후, 인풋에 핸들 달아서 값이 바뀔 때마다 해당 값 user에 저장시킴
입력 폼은 로그인 누르면 submit해서 form에서 함수 실행
해당 값 스프링부트 컨트롤러로 전달
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// CORS 설정
.cors().and()
// CSRF 보호 비활성화
.csrf().disable()
// 인증 필터 설정
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
// URL 규칙 및 권한 설정
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/myPage").authenticated()
.anyRequest().permitAll();
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 쿠키 사용 허용
config.addAllowedOrigin("http://localhost:3000");// 리액트 서버
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
@RequiredArgsConstructor
@Component
public class JwtTokenProvider {
// 임의의 숫자, 문자 아무거나 (Base64로 인코딩 할거라 특수문자 안됨)
private String secretKey = "3d12j3l1k2j3l1k2j3lmdlaskjasdasdqwlkejlk12j3lk123dl23asQWEYZAA";
// 토큰 유효시간 30분
private long tokenValidTime = 30 * 60 * 1000L;
private final UserDetailsService userDetailsService;
// 객체 초기화, secretKey를 Base64로 인코딩
protected void init() {
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
}
// JWT 토큰 생성
public String createToken(String userEmail, String nickname, UserRole roles) {
// claims: JWT payload에 저장되는 정보 단위 (여기서는 주제(subject) 클레임으로 사용)
Claims claims = Jwts.claims().setSubject(userEmail);
// 원하는 정보 put
claims.put("nickname", nickname); // 닉네임 정보 추가
claims.put("roles", roles); // 롤 추가
Date now = new Date();
return Jwts.builder()
.setClaims(claims)// 정보 저장
.setIssuedAt(now) // 토큰 발행 시간 정보
.setExpiration(new Date(now.getTime() + tokenValidTime)) // set Expire Time
.signWith(SignatureAlgorithm.HS256, secretKey) // 사용할 암호화 알고리즘과 signature에 들어갈 secret 값 세팅
.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();
}
// 토큰에서 닉네임만 추출
public String getUserNickname(String token) {
return (String) Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().get("nickname");
}
// 토큰의 유효성 + 만료일자 확인
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;
}
}
}
포스트맨
쿠키 저장