Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions security-admin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies {
implementation project(':domain-user')
implementation project(':domain-base')
implementation project(':domain-token')
implementation project(':application-config')
// SPRING SECURITY
api 'org.springframework.boot:spring-boot-starter-security'
api 'org.springframework.boot:spring-boot-starter-test'
Expand Down
1 change: 1 addition & 0 deletions security-front/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ dependencies {
implementation project(':domain-base')
implementation project(':domain-token')
implementation project(':external-oauth')
implementation project(':application-config')
// SPRING SECURITY
api 'org.springframework.boot:spring-boot-starter-security'
api 'org.springframework.boot:spring-boot-starter-test'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.nowait.frontsecurity.auth.jwt;

import java.io.IOException;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import com.nowait.externaloauth.service.CustomUserDetailService;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RequiredArgsConstructor
@Slf4j
public class JwtAuthorizationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final CustomUserDetailService userDetailsService;

@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
try {
String token = extractTokenFromRequest(request);
if (token != null) {
// 만료 체크
if (jwtUtil.isExpired(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().print("access token expired");
return;
}
// 토큰 category 체크(불필요하면 생략)
String tokenCategory = jwtUtil.getTokenCategory(token);
if (!"accessToken".equals(tokenCategory)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().print("invalid access token");
return;
}
// userId 추출 → UserDetails 조회
Long userId = jwtUtil.getUserId(token);
var userDetails = userDetailsService.loadUserById(userId);
// 인증 객체 생성 및 컨텍스트에 설정
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
} catch (Exception ex) {
log.error("JWT filter error: {}", ex.getMessage());
} finally {
filterChain.doFilter(request, response);
}
}

private String extractTokenFromRequest(HttpServletRequest request) {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
return header.substring(7);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.nowait.frontsecurity.auth.jwt;

import java.nio.charset.StandardCharsets;
import java.util.Date;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.Jwts;

@Component
public class JwtUtil {
private final SecretKey secretKey;

// 시크릿 키를 암호화하여, 키 생성
public JwtUtil(@Value("${jwt.secret}") String secret) {
this.secretKey = new SecretKeySpec(
secret.getBytes(StandardCharsets.UTF_8),
Jwts.SIG.HS256.key().build().getAlgorithm()
);
}

public String createAccessToken(String tokenCategory, Long userId, String role, Long expiredMs) {
return Jwts.builder()
.claim("tokenCategory", tokenCategory) // accessToken
.claim("userId", userId)
.claim("role", role)
.issuedAt(new Date(System.currentTimeMillis()))
.expiration(new Date(System.currentTimeMillis() + expiredMs))
.signWith(secretKey)
.compact();
}

public String createRefreshToken(String tokenCategory, Long userId, Long expiredMs) {
return Jwts.builder()
.claim("tokenCategory", tokenCategory) // refreshToken
.claim("userId", userId)
.issuedAt(new Date(System.currentTimeMillis()))
.expiration(new Date(System.currentTimeMillis() + expiredMs))
.signWith(secretKey)
.compact();
}

public String getTokenCategory(String token) {
return Jwts.parser().verifyWith(secretKey).build()
.parseClaimsJws(token)
.getBody()
.get("tokenCategory", String.class);
}

public String getRole(String token) {
return Jwts.parser().verifyWith(secretKey).build()
.parseClaimsJws(token)
.getBody()
.get("role", String.class);
}

public Long getUserId(String token) {
return Jwts.parser().verifyWith(secretKey).build()
.parseClaimsJws(token)
.getBody()
.get("userId", Long.class);
}

public Boolean isExpired(String token) {
return Jwts.parser().verifyWith(secretKey).build()
.parseSignedClaims(token)
.getPayload()
.getExpiration()
.before(new Date());
}

}