반응형
오늘은 Spring Security를 활용하여 JWT(Json Web Token) 기반 인증 시스템을 구현하는 방법을 배워보겠습니다. Spring Security는 인증 및 권한 관리를 효율적으로 처리할 수 있는 강력한 프레임워크로, JWT와의 연동을 통해 더욱 확장 가능한 인증 시스템을 구축할 수 있습니다.
1. Spring Security의 역할
Spring Security는 다음과 같은 작업을 자동으로 처리합니다:
- 인증(Authentication): 사용자의 신원을 확인
- 인가(Authorization): 사용자의 권한을 확인
- 보안 필터 체인(Security Filter Chain): 요청과 응답 사이의 보안 검증
JWT와 Spring Security를 연동하면 Stateless 인증을 효율적으로 구현할 수 있습니다.
2. 의존성 추가
pom.xml에 Spring Security 관련 의존성을 추가합니다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
</dependency>
3. Spring Security 설정 파일 생성
Spring Security의 설정 파일을 작성합니다.
SecurityConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/login", "/api/register").permitAll() // 인증 불필요한 경로
.anyRequest().authenticated(); // 그 외 경로는 인증 필요
return http.build();
}
}
4. JWT 필터 구현
JWT를 검증하는 필터를 작성하여 Security Filter Chain에 추가합니다.
JwtAuthenticationFilter.java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
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 static final String SECRET_KEY = "my-secret-key";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
String token = authorizationHeader.replace("Bearer ", "");
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
if (claims != null) {
String username = claims.getSubject();
if (username != null) {
JwtUserDetails userDetails = new JwtUserDetails(username); // 사용자 정보
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
chain.doFilter(request, response);
}
}
5. 필터 등록
JwtAuthenticationFilter를 Spring Security의 필터 체인에 등록합니다.
SecurityConfig.java 업데이트
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/login", "/api/register").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
6. JWT 기반 API 구현
로그인 API
@PostMapping("/api/login")
public String login(@RequestBody Map<String, String> credentials) {
String username = credentials.get("username");
String password = credentials.get("password");
if ("user".equals(username) && "password".equals(password)) {
return JwtUtil.generateToken(username);
} else {
throw new RuntimeException("Invalid credentials");
}
}
보호된 API
@GetMapping("/api/secure/data")
public String secureData() {
String username = SecurityContextHolder.getContext().getAuthentication().getName();
return "Hello, " + username + "! You have accessed a secure endpoint.";
}
7. Postman 테스트
- 로그인 API 호출:
- URL: http://localhost:8080/api/login
- Method: POST
- Body:
{ "username": "user", "password": "password" }
- 응답: JWT 토큰 반환
- 보호된 API 호출:
- URL: http://localhost:8080/api/secure/data
- Method: GET
- Header:
- Key: Authorization
- Value: Bearer <발급받은 JWT 토큰>
- 응답: 인증된 사용자 이름 포함 메시지 반환
8. 추가 보안 고려사항
- 토큰 재발급(Refresh Token): 만료된 토큰의 갱신을 위해 Refresh Token을 구현할 수 있습니다.
- 토큰 만료 시 로그아웃 처리: 보안성을 높이기 위해 만료된 토큰의 처리를 철저히 관리해야 합니다.
- HTTP/2 및 HTTPS 사용: 네트워크 상에서 데이터 암호화를 강화합니다.
반응형
'개발 > 전자정부프레임워크' 카테고리의 다른 글
Spring Boot에 데이터 검증 (Validation) 적용하기 (0) | 2024.12.28 |
---|---|
RESTful API에 CORS 설정 적용하기 (0) | 2024.12.28 |
전자정부프레임워크에서 JWT(Json Web Token) 기반 인증 구현 (0) | 2024.12.28 |
전자정부프레임워크에서 API 인증 및 보안 설정 (0) | 2024.12.28 |
전자정부프레임워크에 Swagger 적용하기 (0) | 2024.12.28 |