Admin , Member annotation 추가
rememberMe 쿠키 저장방식 변경 roleHierarchy 적용
This commit is contained in:
parent
6d5649535f
commit
cc5e87af0c
@ -0,0 +1,11 @@
|
||||
package io.company.localhost.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Admin {
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package io.company.localhost.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Member {
|
||||
}
|
||||
@ -1,15 +1,10 @@
|
||||
package io.company.localhost.common.annotation;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ PARAMETER })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface ReqMap {
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
package io.company.localhost.common.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
package io.company.localhost.common.security.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class AuthConfig {
|
||||
|
||||
@ -22,4 +24,9 @@ public class AuthConfig {
|
||||
|
||||
return delegatingPasswordEncoder;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RoleHierarchy roleHierarchy() {
|
||||
return RoleHierarchyImpl.fromHierarchy("ROLE_ADMIN > ROLE_MEMBER > ROLE_ANONYMOUS");
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package io.company.localhost.common.config;
|
||||
package io.company.localhost.common.security.config;
|
||||
|
||||
import io.company.localhost.common.filter.WebCorsFilter;
|
||||
import io.company.localhost.common.security.dsl.RestApiDsl;
|
||||
@ -45,12 +45,10 @@ public class SecurityConfig {
|
||||
final boolean MAX_SESSION_PRENT = false; // 최대 세션 수 초과 시 로그인 방지 여부
|
||||
final String REMEMBER = "remember"; // 'remember me' 기능을 위한 키
|
||||
final String REMEMBER_KEY = "rememberSecretKey";
|
||||
final int REMEMBER_TIME = 60 * 60 * 24 * 365; // 'remember me' 기능의 유효기간 (1년)
|
||||
|
||||
// API 경로 관련 상수 설정
|
||||
final String SECURITY_BASE_URL = "/api/user";
|
||||
final String LOGIN_URL = SECURITY_BASE_URL + "/login";
|
||||
final String INVALID_URL = SECURITY_BASE_URL + "/login/duplicated-login";
|
||||
|
||||
// 보안 필터 체인 설정
|
||||
@Bean
|
||||
@ -89,7 +87,6 @@ public class SecurityConfig {
|
||||
.rememberMe(rm ->
|
||||
rm
|
||||
.key(REMEMBER_KEY)
|
||||
.tokenValiditySeconds(REMEMBER_TIME)
|
||||
.rememberMeParameter(REMEMBER)
|
||||
.rememberMeServices(rememberMeServices()))
|
||||
// 로그인 성공 및 실패 핸들러 설정
|
||||
@ -1,17 +1,17 @@
|
||||
package io.company.localhost.common.security.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.company.localhost.common.exception.code.UserErrorCode;
|
||||
import io.company.localhost.utils.AuthUtil;
|
||||
import io.company.localhost.vo.MemberVo;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.company.localhost.common.exception.code.UserErrorCode;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class RestAuthenticationEntryPointHandler implements AuthenticationEntryPoint {
|
||||
|
||||
@ -21,12 +21,15 @@ public class RestAuthenticationEntryPointHandler implements AuthenticationEntryP
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException authException) throws IOException, ServletException {
|
||||
|
||||
// HTTP 상태 코드를 401 (Unauthorized)로 설정
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
// 응답의 콘텐츠 타입을 JSON으로 설정
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
MemberVo user = AuthUtil.getUser();
|
||||
|
||||
// 사용자 정의 에러 코드와 메시지를 JSON 형식으로 응답
|
||||
if(user != null) {
|
||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
response.getWriter().write(mapper.writeValueAsString(UserErrorCode.INACTIVE_USER.getApiResponse()));
|
||||
}else{
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
response.getWriter().write(mapper.writeValueAsString(UserErrorCode.NOT_AUTH_USER.getApiResponse()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,25 +1,29 @@
|
||||
package io.company.localhost.common.security.manager;
|
||||
|
||||
import io.company.localhost.common.annotation.Admin;
|
||||
import io.company.localhost.common.annotation.Guest;
|
||||
import io.company.localhost.common.annotation.Member;
|
||||
import io.company.localhost.common.security.mapper.MapBasedUrlRoleMapper;
|
||||
import io.company.localhost.common.security.service.DynamicAuthorizationService;
|
||||
import io.company.localhost.common.wrapper.RequestMappingWrapper;
|
||||
import io.company.localhost.utils.ExceptionUtil;
|
||||
import io.company.localhost.vo.MemberVo;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.access.expression.DefaultHttpSecurityExpressionHandler;
|
||||
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
@ -30,10 +34,13 @@ import java.util.stream.Collectors;
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CustomDynamicAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
|
||||
|
||||
List<RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>>> mappings;
|
||||
private static final AuthorizationDecision DENY = new AuthorizationDecision(false);
|
||||
|
||||
private final HandlerMappingIntrospector handlerMappingIntrospector;
|
||||
private final RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||
private final RequestMappingWrapper requestMappingWrapper;
|
||||
private final RoleHierarchy roleHierarchy;
|
||||
|
||||
// 클래스 초기화 후 동적으로 URL-권한 매핑을 설정
|
||||
@PostConstruct
|
||||
@ -51,16 +58,24 @@ public class CustomDynamicAuthorizationManager implements AuthorizationManager<R
|
||||
@Override
|
||||
public AuthorizationResult authorize(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
|
||||
HttpServletRequest request = object.getRequest();
|
||||
|
||||
Authentication auth = authentication.get();
|
||||
|
||||
// @Guest 메서드인지 확인
|
||||
if (isGuestRequest(request) && !(auth.getPrincipal() instanceof MemberVo)) {
|
||||
try {
|
||||
if (requestMappingWrapper.hasAnyAnnotation(request, Guest.class) && !(auth.getPrincipal() instanceof MemberVo)) {
|
||||
boolean allowGuest = !auth.isAuthenticated() || "anonymousUser".equals(auth.getPrincipal());
|
||||
return new AuthorizationDecision(allowGuest);
|
||||
}else if (requestMappingWrapper.hasAnyAnnotation(request, Member.class)) {
|
||||
boolean isMember = auth.isAuthenticated() &&
|
||||
roleHierarchy.getReachableGrantedAuthorities(auth.getAuthorities()).stream()
|
||||
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ROLE_MEMBER")); // 수정
|
||||
return new AuthorizationDecision(isMember);
|
||||
}else if (requestMappingWrapper.hasAnyAnnotation(request, Admin.class)) {
|
||||
boolean isAdmin = auth.isAuthenticated() &&
|
||||
roleHierarchy.getReachableGrantedAuthorities(auth.getAuthorities()).stream()
|
||||
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ROLE_ADMIN")); // 수정
|
||||
return new AuthorizationDecision(isAdmin);
|
||||
}
|
||||
|
||||
|
||||
for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {
|
||||
|
||||
RequestMatcher matcher = mapping.getRequestMatcher();
|
||||
@ -72,35 +87,35 @@ public class CustomDynamicAuthorizationManager implements AuthorizationManager<R
|
||||
new RequestAuthorizationContext(object.getRequest(), matchResult.getVariables()));
|
||||
}
|
||||
}
|
||||
return DENY;
|
||||
}catch (Exception e){
|
||||
ExceptionUtil.messageTrace(e);
|
||||
}
|
||||
|
||||
return new AuthorizationDecision(false);
|
||||
}
|
||||
|
||||
// 역할에 맞는 AuthorizationManager 반환
|
||||
private AuthorizationManager<RequestAuthorizationContext> customAuthorizationManager(String role) {
|
||||
if (role.startsWith("ROLE")) {
|
||||
return AuthorityAuthorizationManager.hasAuthority(role);
|
||||
AuthorityAuthorizationManager<RequestAuthorizationContext> objectAuthorityAuthorizationManager =
|
||||
AuthorityAuthorizationManager.hasAuthority(role);
|
||||
objectAuthorityAuthorizationManager.setRoleHierarchy(roleHierarchy);
|
||||
|
||||
return objectAuthorityAuthorizationManager;
|
||||
}else{
|
||||
return new WebExpressionAuthorizationManager(role);
|
||||
DefaultHttpSecurityExpressionHandler expressionHandler = new DefaultHttpSecurityExpressionHandler();
|
||||
expressionHandler.setRoleHierarchy(roleHierarchy);
|
||||
|
||||
WebExpressionAuthorizationManager webExpressionAuthorizationManager =
|
||||
new WebExpressionAuthorizationManager(role);
|
||||
|
||||
webExpressionAuthorizationManager.setExpressionHandler(expressionHandler);
|
||||
|
||||
return webExpressionAuthorizationManager;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// @Guest가 적용된 요청인지 확인
|
||||
private boolean isGuestRequest(HttpServletRequest request) {
|
||||
try {
|
||||
HandlerExecutionChain handlerExecutionChain = requestMappingHandlerMapping.getHandler(request);
|
||||
|
||||
if (handlerExecutionChain != null) {
|
||||
Object handler = handlerExecutionChain.getHandler();
|
||||
if (handler instanceof HandlerMethod handlerMethod) {
|
||||
return handlerMethod.getMethod().isAnnotationPresent(Guest.class); }
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void verify(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
|
||||
|
||||
@ -10,14 +10,11 @@ public class MapBasedUrlRoleMapper implements UrlRoleMapper{
|
||||
|
||||
final String PERMIT_ALL = "permitAll";
|
||||
final String ROLE_MEMBER = "ROLE_MEMBER";
|
||||
final String ROLE_MANAGER = "ROLE_MANAGER";
|
||||
final String ROLE_ADMIN = "ROLE_ADMIN";
|
||||
|
||||
@Override
|
||||
public Map<String, String> getUrlRoleMappings() {
|
||||
urlRoleMappings.put("/api/login", PERMIT_ALL);
|
||||
urlRoleMappings.put("/api/user/**", ROLE_MEMBER);
|
||||
urlRoleMappings.put("/api/user/logout", PERMIT_ALL);
|
||||
urlRoleMappings.put("/api/test/**", ROLE_MEMBER);
|
||||
|
||||
|
||||
|
||||
@ -1,32 +1,35 @@
|
||||
package io.company.localhost.common.security.service;
|
||||
|
||||
import static org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.*;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
|
||||
import io.company.localhost.common.security.details.MemberPrincipalDetails;
|
||||
import io.company.localhost.vo.MemberVo;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
@Slf4j
|
||||
public class CustomRememberMeServices implements RememberMeServices {
|
||||
|
||||
private static final String REMEMBER_ME_KEY = "remember";
|
||||
private final UserDetailsService userDetailsService;
|
||||
private final String key;
|
||||
private static final String REMEMBER_ME_COOKIE_NAME = "remember-me";
|
||||
private static final long TOKEN_VALIDITY_SECONDS = 60 * 60 * 24 * 365; // 1 year
|
||||
private static final String DELIMITER = ":";
|
||||
|
||||
public CustomRememberMeServices(String key, UserDetailsService userDetailsService) {
|
||||
this.key = key;
|
||||
private final String secretKey;
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
public CustomRememberMeServices(String secretKey, UserDetailsService userDetailsService) {
|
||||
this.secretKey = secretKey;
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
@ -35,26 +38,39 @@ public class CustomRememberMeServices implements RememberMeServices {
|
||||
|
||||
Cookie rememberMeCookie = getRememberMeCookie(request);
|
||||
if (rememberMeCookie == null) {
|
||||
log.debug("No remember-me cookie found");
|
||||
return null;
|
||||
}
|
||||
|
||||
String username = decodeCookie(rememberMeCookie.getValue());
|
||||
if (username == null || username.isEmpty()) {
|
||||
log.error("Invalid remember-me cookie");
|
||||
String[] tokenParts = decodeAndSplitCookie(rememberMeCookie.getValue());
|
||||
if (tokenParts == null || tokenParts.length != 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String username = tokenParts[0];
|
||||
long expiryTime;
|
||||
try {
|
||||
expiryTime = Long.parseLong(tokenParts[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String signature = tokenParts[2];
|
||||
if (!isTokenValid(username, expiryTime, signature)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() > expiryTime) {
|
||||
return null;
|
||||
}
|
||||
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
|
||||
if (userDetails != null) {
|
||||
MemberPrincipalDetails memberDetails = (MemberPrincipalDetails) userDetails;
|
||||
MemberVo memberVo = memberDetails.member();
|
||||
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(key, memberVo, userDetails.getAuthorities());
|
||||
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(secretKey, memberVo, userDetails.getAuthorities());
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
return auth;
|
||||
}else {
|
||||
log.error("UserDetailsService returned null for username: {}", username);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -62,58 +78,77 @@ public class CustomRememberMeServices implements RememberMeServices {
|
||||
|
||||
@Override
|
||||
public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
|
||||
|
||||
Boolean rememberMe = (Boolean) request.getAttribute(REMEMBER_ME_KEY);
|
||||
if (rememberMe != null && rememberMe) {
|
||||
// Remember-Me 토큰 생성 및 설정
|
||||
Object principal = successfulAuthentication.getPrincipal();
|
||||
MemberVo member = (MemberVo)principal;
|
||||
String username = member.getLoginId();
|
||||
String rememberMeToken = generateRememberMeToken(username);
|
||||
int tokenValiditySeconds = getTokenValiditySeconds();
|
||||
if (!(principal instanceof MemberVo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Cookie rememberMeCookie = new Cookie(SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, rememberMeToken);
|
||||
MemberVo member = (MemberVo) principal;
|
||||
MemberPrincipalDetails details = new MemberPrincipalDetails(member);
|
||||
String username = member.getLoginId();
|
||||
long expiryTime = System.currentTimeMillis() + (TOKEN_VALIDITY_SECONDS * 1000);
|
||||
String signature = generateSignature(username, expiryTime);
|
||||
String tokenValue = encodeToken(username, expiryTime, signature);
|
||||
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(successfulAuthentication);
|
||||
|
||||
Cookie rememberMeCookie = new Cookie(REMEMBER_ME_COOKIE_NAME, tokenValue);
|
||||
rememberMeCookie.setPath("/");
|
||||
rememberMeCookie.setMaxAge(tokenValiditySeconds);
|
||||
rememberMeCookie.setMaxAge((int) TOKEN_VALIDITY_SECONDS);
|
||||
rememberMeCookie.setHttpOnly(true);
|
||||
rememberMeCookie.setSecure(request.isSecure());
|
||||
response.addCookie(rememberMeCookie);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loginFail(HttpServletRequest request, HttpServletResponse response) {
|
||||
// 로그인 실패 처리
|
||||
Cookie cookie = new Cookie(REMEMBER_ME_COOKIE_NAME, null);
|
||||
cookie.setPath("/");
|
||||
cookie.setMaxAge(0);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
private Cookie getRememberMeCookie(HttpServletRequest request) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies == null) {
|
||||
if (request.getCookies() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for(Cookie cookie : cookies) {
|
||||
if(SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY.equals(cookie.getName())) {
|
||||
for (Cookie cookie : request.getCookies()) {
|
||||
if (REMEMBER_ME_COOKIE_NAME.equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String decodeCookie(String cookieValue) {
|
||||
try { // Base64 디코딩
|
||||
return new String(Base64.getDecoder().decode(cookieValue));
|
||||
} catch (IllegalArgumentException e) {
|
||||
private String[] decodeAndSplitCookie(String cookieValue) {
|
||||
try {
|
||||
String decodedValue = new String(Base64.getDecoder().decode(cookieValue), StandardCharsets.UTF_8);
|
||||
return decodedValue.split(DELIMITER);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to decode remember-me cookie", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String generateRememberMeToken(String username) {
|
||||
return Base64.getEncoder().encodeToString(username.getBytes());
|
||||
private String encodeToken(String username, long expiryTime, String signature) {
|
||||
String tokenValue = username + DELIMITER + expiryTime + DELIMITER + signature;
|
||||
return Base64.getEncoder().encodeToString(tokenValue.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private int getTokenValiditySeconds() {
|
||||
return 60 * 60 * 24 * 365;
|
||||
private boolean isTokenValid(String username, long expiryTime, String signature) {
|
||||
String expectedSignature = generateSignature(username, expiryTime);
|
||||
return expectedSignature.equals(signature);
|
||||
}
|
||||
|
||||
private String generateSignature(String username, long expiryTime) {
|
||||
try {
|
||||
String data = username + DELIMITER + expiryTime;
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
|
||||
return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes(StandardCharsets.UTF_8)));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to generate signature", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
package io.company.localhost.controller.common;
|
||||
|
||||
import static org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.company.localhost.common.annotation.Admin;
|
||||
import io.company.localhost.common.annotation.Guest;
|
||||
import io.company.localhost.common.annotation.Member;
|
||||
import io.company.localhost.common.response.ApiResponse;
|
||||
import io.company.localhost.utils.AuthUtil;
|
||||
import io.company.localhost.utils.SessionListener;
|
||||
import io.company.localhost.vo.MemberVo;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
@ -16,16 +24,10 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.company.localhost.common.response.ApiResponse;
|
||||
import io.company.localhost.utils.AuthUtil;
|
||||
import io.company.localhost.utils.SessionListener;
|
||||
import io.company.localhost.vo.MemberVo;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@ -72,7 +74,7 @@ public class UserController {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
boolean remember = false;
|
||||
|
||||
if (authentication != null && authentication instanceof RememberMeAuthenticationToken) {
|
||||
if (authentication instanceof RememberMeAuthenticationToken) {
|
||||
remember = true;
|
||||
}
|
||||
// 쿠키 확인
|
||||
@ -94,6 +96,7 @@ public class UserController {
|
||||
|
||||
|
||||
//로그아웃
|
||||
@Guest
|
||||
@GetMapping("/logout")
|
||||
public ApiResponse<String> logout(HttpServletRequest request, HttpServletResponse response) {
|
||||
String returnMessage = "Successfully logged out";
|
||||
@ -117,4 +120,22 @@ public class UserController {
|
||||
}
|
||||
|
||||
|
||||
@Guest
|
||||
@GetMapping("get1")
|
||||
public ApiResponse<?> getAuthTest1() {
|
||||
return ApiResponse.ok(AuthUtil.getUser());
|
||||
}
|
||||
|
||||
@Member
|
||||
@GetMapping("get2")
|
||||
public ApiResponse<?> getAuthTest2() {
|
||||
return ApiResponse.ok(AuthUtil.getUser());
|
||||
}
|
||||
|
||||
@Admin
|
||||
@GetMapping("get3")
|
||||
public ApiResponse<?> getAuthTest3() {
|
||||
return ApiResponse.ok(AuthUtil.getUser());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user