반응형
JWT(JSON Web Token)를 활용하여 전자정부프레임워크에서 토큰 기반 인증을 구현하는 방법을 학습합니다. JWT는 클라이언트와 서버 간의 인증 및 권한 관리를 위한 효율적이고 안전한 방식입니다.
1. JWT란?
JWT는 JSON 포맷을 사용해 정보를 안전하게 전달하는 토큰입니다.
- 구조:
- Header: 토큰 타입(JWT)과 서명 알고리즘(예: HMAC, RSA)
- Payload: 클레임(Claims)이라고 불리는 사용자 데이터
- Signature: 헤더와 페이로드를 암호화하여 생성
토큰 예시:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6IlVTRVIiLCJpYXQiOjE2MjAwMDAwMDAsImV4cCI6MTYyMDAwMzYwMH0
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
2. JWT 활용 인증 구조
- 클라이언트가 서버에 로그인 요청을 보냄.
- 서버는 로그인 정보 검증 후 JWT 발급.
- 클라이언트는 JWT를 저장(LocalStorage, SessionStorage 등)하고 요청 시마다 헤더에 첨부.
- 서버는 JWT를 검증하여 사용자 인증 수행.
3. JWT 기반 인증 구현
3-1. 의존성 추가
pom.xml에 JWT 라이브러리를 추가합니다.
<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-2. JWT 유틸리티 클래스 작성
JwtUtil.java
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtil {
private static final String SECRET_KEY = "secretKey";
private static final long EXPIRATION_TIME = 1000 * 60 * 60; // 1시간
// 토큰 생성
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
// 토큰 검증
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}
// 사용자 이름 추출
public String extractUsername(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
3-3. 컨트롤러 작성
AuthController.java
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
private final JwtUtil jwtUtil;
public AuthController(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
// 실제로는 DB에서 사용자 인증 정보를 확인해야 합니다.
if ("admin".equals(username) && "password".equals(password)) {
return jwtUtil.generateToken(username);
}
return "인증 실패";
}
@GetMapping("/validate")
public String validateToken(@RequestParam String token) {
if (jwtUtil.validateToken(token)) {
return "유효한 토큰";
}
return "유효하지 않은 토큰";
}
}
3-4. JWT 필터 작성
JwtFilter.java
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class JwtFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
public JwtFilter(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
if (jwtUtil.validateToken(jwt)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
username, null, new ArrayList<>());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
chain.doFilter(request, response);
}
}
4. 테스트
- 로그인 요청:
- URL: /auth/login
- 파라미터: username=admin&password=password
- 응답: JWT 토큰 반환
- 유효성 검증:
- URL: /auth/validate
- 파라미터: token=<발급받은 JWT>
- 응답: "유효한 토큰" 또는 "유효하지 않은 토큰"
- 보호된 리소스 요청:
- Authorization 헤더에 Bearer <JWT>를 포함하여 요청.
5. 마무리
JWT 기반 인증은 서버 세션에 의존하지 않으므로 확장성이 높고, 분산 시스템에서 효율적입니다. 다음에서는 API 서버와 클라이언트 간의 데이터 암호화 및 보안에 대해 학습합니다.
반응형
'개발 > 전자정부프레임워크' 카테고리의 다른 글
OAuth 2.0을 이용한 소셜 로그인 구현 (0) | 2024.12.26 |
---|---|
API 서버와 클라이언트 간의 데이터 암호화 및 보안 (0) | 2024.12.26 |
Spring Security를 활용한 인증 및 권한 관리 (0) | 2024.12.26 |
RESTful 웹 서비스 개발 (0) | 2024.12.25 |
Ajax를 활용한 비동기 통신 구현 (0) | 2024.12.25 |