Skip to content

Commit

Permalink
FEAT: JwtFilter 기능
Browse files Browse the repository at this point in the history
  • Loading branch information
saewoo1 committed Jan 26, 2025
1 parent 3d1a8cb commit 0596715
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ public String createUserToken(User user, LocalDateTime now) {
.compact();
}

public String createUserToken(User user, String provider, LocalDateTime now) {
Claims claims = Jwts.claims();
claims.put("email", user.getEmail());
claims.put("name", user.getName());
claims.put("blackholedAt", user.getBlackholedAtString());
claims.put("role", user.getRole());
claims.put("provider", provider);

return Jwts.builder()
.setClaims(claims)
.signWith(jwtProperties.getSigningKey(), SignatureAlgorithm.HS256)
.setExpiration(Timestamp.valueOf(now.plusDays(jwtProperties.getExpiryDays())))
.compact();
}

/**
* JWT 토큰을 생성합니다.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import java.security.Key;
import java.util.Base64;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -84,7 +86,8 @@ public boolean isValidTokenWithLevel(String token, AuthLevel authLevel)
*/
public boolean isTokenValid(String token, Key key) {
try {
Jwts.parserBuilder().setSigningKey(key).build()
Jwts.parserBuilder()
.setSigningKey(key).build()
.parseClaimsJws(token);
return true;
} catch (MalformedJwtException e) {
Expand Down Expand Up @@ -143,4 +146,25 @@ private boolean isMaster(String email) {
private boolean isUser(String email) {
return userQueryService.findUserByEmail(email).isPresent();
}

// Jwt 관련
public Claims parseToken(String token) {
try {
return Jwts.parserBuilder()
.setSigningKey(jwtProperties.getSigningKey()).build()
.parseClaimsJws(token)
.getBody();
} catch (MalformedJwtException e) {
throw ExceptionStatus.JWT_MALFORMED.asSpringSecurityException();
} catch (ExpiredJwtException e) {
throw ExceptionStatus.JWT_EXPIRED.asSpringSecurityException();
} catch (UnsupportedJwtException e) {
throw ExceptionStatus.JWT_UNSUPPORTED.asSpringSecurityException();
} catch (SignatureException e) {
throw ExceptionStatus.JWT_SIGNATURE.asSpringSecurityException();
} catch (IllegalArgumentException e) {
throw ExceptionStatus.INVALID_JWT_TOKEN.asSpringSecurityException();
}
}

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package org.ftclub.cabinet.config.security;

import io.jsonwebtoken.Claims;
import java.io.IOException;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ftclub.cabinet.auth.domain.CookieManager;
import org.ftclub.cabinet.auth.service.TokenProvider;
import org.ftclub.cabinet.auth.service.TokenValidator;
import org.ftclub.cabinet.exception.ExceptionStatus;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

Expand All @@ -20,8 +25,7 @@
public class JwtAuthenticationFilter extends OncePerRequestFilter {

private static final String BEARER = "Bearer ";
private final TokenProvider tokenProvider;
private final CookieManager cookieManager;
private final TokenValidator tokenValidator;

/**
* JWT에 대한 검증을 진행한 후, contextHolder에 유저에 대한 정보를 저장합니다.
Expand All @@ -35,21 +39,36 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {

try {
String accessToken = extractToken(request);

Claims claims = tokenValidator.parseToken(accessToken);
updateSecurityContextHolder(claims);
} catch (Exception e) {

}
filterChain.doFilter(request, response);
}


private String extractToken(HttpServletRequest request) {
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header == null || !header.startsWith(BEARER)) {
throw ExceptionStatus.NOT_FOUND_JWT_TOKEN.asSpringSecurityException();
}
return header.substring(BEARER.length());
}

private void updateSecurityContextHolder(Claims claims) {

CustomOauth2User updateUser =
new CustomOauth2User(claims.get("provider", String.class),
claims.get("name", String.class), claims);

List<GrantedAuthority> authorityList =
List.of(new SimpleGrantedAuthority("ROLE_" + claims.get("role", String.class)));
UsernamePasswordAuthenticationToken newAuth =
new UsernamePasswordAuthenticationToken(updateUser, null, authorityList);
SecurityContextHolder.getContext().setAuthentication(newAuth);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

private final CustomAccessDeniedHandler customAccessDeniedHandler;
private final CustomOAuth2UserService customOAuth2UserService;
private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final CustomSuccessHandler customSuccessHandler;
private final AuthenticationEntryPoint entrypoint;

@Bean
Expand All @@ -42,7 +44,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
)
.oauth2Login(oauth -> oauth
.userInfoEndpoint(user -> user.userService(customOAuth2UserService))
.successHandler(customSuccessHandler)
)
.addFilterBefore(jwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(handler -> handler.authenticationEntryPoint(entrypoint))
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,13 @@ public void addBulkCoin(List<Long> userIds, Long amount) {
userRepository.updateBulkUserCoin(userIds, amount);
}

public void linkOauthAccount(String name, String email) {
public User linkOauthAccount(String name, String email) {
User user = userRepository.findByName(name)
.orElseThrow(ExceptionStatus.NOT_FOUND_USER::asServiceException);
if (user.getOauthMail() != null) {
throw ExceptionStatus.OAUTH_EMAIL_ALREADY_LINKED.asSpringSecurityException();
}
user.changeOauthMail(email);
userRepository.save(user);
return userRepository.save(user);
}
}

0 comments on commit 0596715

Please sign in to comment.