JWT
Json Web Token
웹 애플리케이션 간에 정보를 안전하게 전송하기 위한 개방형 표준(RFC 7519)
JWT는 세가지 부분으로 구성된다.
Header: 토큰의 유형과 해싱 알고리즘 등의 메타데이터가 json 형식으로 포함
Payload: 클레임이라 부르는 사용자의 id및 권한등이 포함
Signature: Header와 Payload를 인코딩하고 서명하여 토큰의 유효성을 검증한다.
JWT를 발급하고 검증해보자.
스프링 시큐리티를 사용해 구현할 수 있다.
1. 의존성 추가 pom.xml/build.gradle 파일에 필요한 의존성을 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version> <!-- 현재 버전 확인 필요 -->
</dependency>
2. JWT 설정을 담당할 클래스를 생성
JwtUtil클래스는 JWT 생성, 유효성 검증 및 클레임 추출 등의 기능을 담당한다.
SECRET_KEY와 expiration 값을 application.proerties 또는 application.yml파일에서 관리하도록 설정.
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String SECRET_KEY;
@Value("${jwt.expiration}")
private Long expiration;
// JWT 토큰에서 클레임을 추출합니다.
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
// JWT 토큰에서 만료 날짜를 추출합니다.
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
// JWT 토큰에서 모든 클레임을 추출합니다.
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
// 토큰이 만료되었는지 확인합니다.
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
// 유저 정보를 바탕으로 JWT 토큰을 생성합니다.
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
// 토큰 생성 및 서명합니다.
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
}
// 토큰의 유효성을 검사합니다.
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
// 토큰에서 사용자 이름을 추출합니다.
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
}
3. 시큐리티 설정 클래스를 적용하여 JWT인증을 적용
SecurityConfigurer클래스는 사용자 인증 및 JWT 필터 설정을 담당.
JwtRequestFilter는 클라이언트에서 전달된 JWT 토큰을 검증하고 유효한 경우에만 인증을 통화시킨다.
@Configuration
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/authenticate").permitAll() // 인증 요청은 모두 허용
.anyRequest().authenticated(); // 그 외 요청은 인증 필요
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
외 추가적인 비즈니스 로직을 구현하거나 보안 설정을 더 강화할 수 있다.
'이론' 카테고리의 다른 글
인수의 순서에 관계없이 값을 전달하다, Named argument 명명된 인수 (0) | 2024.08.06 |
---|---|
증분 백업이란? (feat.차등 백업) (0) | 2024.08.05 |
SDK란?: SDK와 JDK (0) | 2024.07.08 |
Flutter와 Dart (0) | 2024.07.08 |
회귀분석이란?: 단순회귀분석, 다중회귀분석 (0) | 2024.06.26 |