요약: 이 글에서는 Spring Boot 기반의 웹 애플리케이션에서 JSON Web Token(JWT)을 사용하여 인증 및 인가를 구현하는 방법을 소개합니다. 개발자들이 일하다가 모르는 것이 있다면 이 글을 참고하여 JWT를 이용한 인증 및 인가 구현을 더 효과적으로 설계하고 구현할 수 있습니다.
JWT란?
JSON Web Token(JWT)은 웹 애플리케이션에서 사용되는 인증 및 인가 메커니즘 중 하나로, 간단하고 안전한 방법으로 서버와 클라이언트 사이에 정보를 전달할 수 있습니다. JWT는 헤더(header), 페이로드(payload), 시그니처(signature)의 세 부분으로 구성되어 있으며, 각 부분은 Base64Url 인코딩을 통해 문자열로 변환된 후 마침표(.)로 연결되어 생성됩니다.
필요한 의존성 추가
먼저, Spring Boot 프로젝트에 JWT를 사용하기 위해 필요한 의존성을 추가해야 합니다. pom.xml 파일에 다음과 같이 jjwt 라이브러리를 추가합니다.
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
JWT 유틸리티 클래스 생성
JWT를 생성하고 검증하는 유틸리티 클래스를 생성합니다. 이 클래스에서는 JWT를 생성할 때 사용할 비밀키를 정의하고, JWT의 생성 및 검증 메서드를 구현합니다.
예시:
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtil {
private final String secretKey = "mySecretKey";
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000)) // 1시간 동안 유효
.signWith(SignatureAlgorithm.HS512, secretKey)
.compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}
}
인증 및 인가 필터 생성
JWT를 사용하여 인증 및 인가를 처리하는 필터를 생성합니다. 이 필터에서는 사용자의 요청을 검사하여 JWT 토큰이 유효한지 확인하고, 유효한 경우 사용자의 인증 정보를 Spring Security 컨텍스트에 설정합니다.
예시:
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
public JwtAuthenticationFilter(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
String token = authorizationHeader.substring(7);
String username = jwtUtil.getUsernameFromToken(token);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
if (jwtUtil.validateToken(token)) {
Authentication authentication = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
filterChain.doFilter(request, response);
}
}
Spring Security 설정 업데이트
Spring Security 설정을 업데이트하여 JWT 인증 필터를 추가하고, 인증 요청이 필요한 엔드포인트를 정의합니다.
예시:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
private final JwtUtil jwtUtil;
public SecurityConfig(UserDetailsService userDetailsService, JwtUtil jwtUtil) {
this.userDetailsService = userDetailsService;
this.jwtUtil = jwtUtil;
}
@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("/api/authenticate").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new JwtAuthenticationFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
이제 Spring Boot 웹 애플리케이션에서 JWT를 사용하여 인증 및 인가를 처리할 수 있습니다. 클라이언트는 사용자 인증을 위해 /api/authenticate 엔드포인트에 요청을 보내고, 성공적으로 인증된 경우 JWT 토큰을 받습니다. 이 토큰은 이후의 요청에서 "Authorization" 헤더에 "Bearer {토큰}" 형식으로 포함되어야 합니다. 토큰이 유효한 경우, 사용자는 인증이 필요한 엔드포인트에 접근할 수 있습니다.
사용자 인증 엔드포인트 추가
마지막으로, 사용자 인증을 위한 엔드포인트를 추가해야 합니다. 사용자가 제공한 이메일과 비밀번호를 검증하고, 성공적으로 인증된 경우 JWT 토큰을 생성하여 반환합니다.
예시:
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class AuthenticationController {
private final AuthenticationManager authenticationManager;
private final JwtUtil jwtUtil;
public AuthenticationController(AuthenticationManager authenticationManager, JwtUtil jwtUtil) {
this.authenticationManager = authenticationManager;
this.jwtUtil = jwtUtil;
}
@PostMapping("/authenticate")
public ResponseEntity<?> authenticate(@RequestBody AuthenticationRequest authenticationRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authenticationRequest.getEmail(), authenticationRequest.getPassword())
);
String token = jwtUtil.generateToken(authentication.getName());
return ResponseEntity.ok(new AuthenticationResponse(token));
}
}
이제 클라이언트는 사용자 인증을 위해 /api/authenticate 엔드포인트에 요청을 보낼 수 있으며, 서버는 이를 처리하여 적절한 JWT 토큰을 반환합니다. 이 토큰은 클라이언트가 이후의 요청에서 사용하여 인증 및 인가를 처리할 수 있게 됩니다.
이 글에서는 Spring Boot 기반의 웹 애플리케이션에서 JWT를 사용하여 인증 및 인가를 구현하는 방법을 설명했습니다. 이를 통해 개발자들은 안전하고 효과적인 인증 및 인가 메커니즘을 쉽게 구현할 수 있습니다. 만약 개발 과정에서 문제가 발생하거나 추가 정보가 필요한 경우, 이 글을 참조하여 필요한 내용을 검색하고 찾아볼 수 있습니다.
#SpringBoot #JWT #인증 #인가 #JSONWebToken #WebApplication #API #Security #Java #프로그래밍
'자기개발 > 검색한 자료 정리' 카테고리의 다른 글
Git 브랜치 전략과 실제 프로젝트에서의 활용 (0) | 2023.04.19 |
---|---|
React와 Redux를 사용한 프론트엔드 상태 관리 (0) | 2023.04.19 |
REST API 디자인 원칙과 Best Practices (0) | 2023.04.19 |
Java stream list 배열 변환 (3) | 2022.07.30 |
Java 이항연산자 대신 optional 사용 (2) | 2022.07.30 |