-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[INIT] 시큐리티 및 jwt 기초 세팅 및 카카오 로그인 구현
- Loading branch information
Showing
24 changed files
with
612 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
src/main/java/com/soptie/server/auth/controller/AuthController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.soptie.server.auth.controller; | ||
|
||
import com.soptie.server.auth.dto.SignInRequest; | ||
import com.soptie.server.auth.message.ResponseMessage; | ||
import com.soptie.server.auth.service.AuthService; | ||
import com.soptie.server.common.dto.Response; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.val; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import static com.soptie.server.common.dto.Response.success; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("api/v1/auth") | ||
public class AuthController { | ||
|
||
private final AuthService authService; | ||
|
||
@PostMapping | ||
public ResponseEntity<Response> signIn(@RequestHeader("Authorization") String socialAccessToken, @RequestBody SignInRequest request) { | ||
val response = authService.signIn(socialAccessToken, request); | ||
return ResponseEntity.ok(success(ResponseMessage.SUCCESS_SIGNIN.getMessage(), response)); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/soptie/server/auth/dto/SignInRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.soptie.server.auth.dto; | ||
|
||
import com.soptie.server.member.entity.SocialType; | ||
|
||
public record SignInRequest( | ||
SocialType socialType | ||
) { | ||
|
||
public static SignInRequest of(SocialType socialType) { | ||
return new SignInRequest(socialType); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/main/java/com/soptie/server/auth/dto/SignInResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.soptie.server.auth.dto; | ||
|
||
import com.soptie.server.auth.vo.Token; | ||
import lombok.Builder; | ||
|
||
@Builder | ||
public record SignInResponse( | ||
String accessToken, | ||
String refreshToken | ||
) { | ||
|
||
public static SignInResponse of(Token token) { | ||
return SignInResponse.builder() | ||
.accessToken(token.getAccessToken()) | ||
.refreshToken(token.getRefreshToken()) | ||
.build(); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
src/main/java/com/soptie/server/auth/jwt/CustomJwtAuthenticationEntryPoint.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.soptie.server.auth.jwt; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.soptie.server.common.dto.Response; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.AuthenticationException; | ||
import org.springframework.security.web.AuthenticationEntryPoint; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.IOException; | ||
|
||
import static com.soptie.server.auth.message.ErrorMessage.INVALID_TOKEN; | ||
import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; | ||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class CustomJwtAuthenticationEntryPoint implements AuthenticationEntryPoint { | ||
|
||
private final ObjectMapper objectMapper; | ||
|
||
@Override | ||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { | ||
setResponse(response); | ||
} | ||
|
||
private void setResponse(HttpServletResponse response) throws IOException { | ||
response.setCharacterEncoding("UTF-8"); | ||
response.setContentType(APPLICATION_JSON_VALUE); | ||
response.setStatus(SC_UNAUTHORIZED); | ||
response.getWriter().println(objectMapper.writeValueAsString(Response.fail(INVALID_TOKEN.getMessage()))); | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
src/main/java/com/soptie/server/auth/jwt/JwtAuthenticationFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.soptie.server.auth.jwt; | ||
|
||
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; | ||
import lombok.val; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.filter.OncePerRequestFilter; | ||
|
||
import java.io.IOException; | ||
|
||
import static com.soptie.server.auth.jwt.JwtValidationType.VALID_JWT; | ||
import static io.jsonwebtoken.lang.Strings.hasText; | ||
import static org.springframework.http.HttpHeaders.AUTHORIZATION; | ||
|
||
@Slf4j | ||
@Component | ||
@RequiredArgsConstructor | ||
public class JwtAuthenticationFilter extends OncePerRequestFilter { | ||
|
||
private static final String BEARER_HEADER = "Bearer "; | ||
private static final String BLANK = ""; | ||
|
||
private final JwtTokenProvider jwtTokenProvider; | ||
|
||
@Override | ||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { | ||
try { | ||
val token = getAccessTokenFromRequest(request); | ||
if (hasText(token) && jwtTokenProvider.validateToken(token) == VALID_JWT) { | ||
val authentication = new UserAuthentication(getMemberId(token), null, null); | ||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); | ||
SecurityContextHolder.getContext().setAuthentication(authentication); | ||
} | ||
} catch (Exception exception) { | ||
log.error(exception.getMessage()); | ||
} | ||
|
||
filterChain.doFilter(request, response); | ||
} | ||
|
||
private Long getMemberId(String token) { | ||
return jwtTokenProvider.getUserFromJwt(token); | ||
} | ||
|
||
private String getAccessTokenFromRequest(HttpServletRequest request) { | ||
return isContainsAccessToken(request) ? getAuthorizationAccessToken(request) : null; | ||
} | ||
|
||
private boolean isContainsAccessToken(HttpServletRequest request) { | ||
val authorization = request.getHeader(AUTHORIZATION); | ||
return authorization != null && authorization.startsWith(BEARER_HEADER); | ||
} | ||
|
||
private String getAuthorizationAccessToken(HttpServletRequest request) { | ||
return request.getHeader(AUTHORIZATION).replaceFirst(BEARER_HEADER, BLANK); | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
src/main/java/com/soptie/server/auth/jwt/JwtTokenProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package com.soptie.server.auth.jwt; | ||
|
||
import com.soptie.server.common.config.ValueConfig; | ||
import io.jsonwebtoken.*; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import lombok.val; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.stereotype.Component; | ||
|
||
import javax.crypto.SecretKey; | ||
import java.util.Date; | ||
|
||
import static com.soptie.server.auth.jwt.JwtValidationType.*; | ||
import static io.jsonwebtoken.Header.*; | ||
import static io.jsonwebtoken.security.Keys.hmacShaKeyFor; | ||
import static java.util.Base64.getEncoder; | ||
|
||
@Slf4j | ||
@Component | ||
@RequiredArgsConstructor | ||
public class JwtTokenProvider { | ||
|
||
private final ValueConfig valueConfig; | ||
|
||
public String generateToken(Authentication authentication, Long expiration) { | ||
return Jwts.builder() | ||
.setHeaderParam(TYPE, JWT_TYPE) | ||
.setClaims(generateClaims(authentication)) | ||
.setIssuedAt(new Date(System.currentTimeMillis())) | ||
.setExpiration(new Date(System.currentTimeMillis() + expiration)) | ||
.signWith(getSigningKey()) | ||
.compact(); | ||
} | ||
|
||
public JwtValidationType validateToken(String token) { | ||
try { | ||
getBody(token); | ||
return VALID_JWT; | ||
} catch (MalformedJwtException exception) { | ||
log.error(exception.getMessage()); | ||
return INVALID_JWT_TOKEN; | ||
} catch (ExpiredJwtException exception) { | ||
log.error(exception.getMessage()); | ||
return EXPIRED_JWT_TOKEN; | ||
} catch (UnsupportedJwtException exception) { | ||
log.error(exception.getMessage()); | ||
return UNSUPPORTED_JWT_TOKEN; | ||
} catch (IllegalArgumentException exception) { | ||
log.error(exception.getMessage()); | ||
return EMPTY_JWT; | ||
} | ||
} | ||
|
||
private Claims generateClaims(Authentication authentication) { | ||
val claims = Jwts.claims(); | ||
claims.put("memberId", authentication.getPrincipal()); | ||
return claims; | ||
} | ||
|
||
public Long getUserFromJwt(String token) { | ||
val claims = getBody(token); | ||
return Long.parseLong(claims.get("memberId").toString()); | ||
} | ||
|
||
private Claims getBody(final String token) { | ||
return Jwts.parserBuilder() | ||
.setSigningKey(getSigningKey()) | ||
.build() | ||
.parseClaimsJws(token) | ||
.getBody(); | ||
} | ||
|
||
private SecretKey getSigningKey() { | ||
val encodedKey = getEncoder().encodeToString(valueConfig.getSecretKey().getBytes()); | ||
return hmacShaKeyFor(encodedKey.getBytes()); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/soptie/server/auth/jwt/JwtValidationType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.soptie.server.auth.jwt; | ||
|
||
public enum JwtValidationType { | ||
VALID_JWT, | ||
INVALID_JWT_SIGNATURE, | ||
INVALID_JWT_TOKEN, | ||
EXPIRED_JWT_TOKEN, | ||
UNSUPPORTED_JWT_TOKEN, | ||
EMPTY_JWT | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/com/soptie/server/auth/jwt/UserAuthentication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.soptie.server.auth.jwt; | ||
|
||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.GrantedAuthority; | ||
|
||
import java.util.Collection; | ||
|
||
public class UserAuthentication extends UsernamePasswordAuthenticationToken { | ||
|
||
public UserAuthentication(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) { | ||
super(principal, credentials, authorities); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/com/soptie/server/auth/message/ErrorMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.soptie.server.auth.message; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
@Getter | ||
public enum ErrorMessage { | ||
|
||
EMPTY_ACCESS_TOKEN("액세스 토큰이 없습니다."), | ||
EMPTY_REFRESH_TOKEN("리프레시 토큰이 없습니다"), | ||
INVALID_TOKEN("유효하지 않은 토큰입니다"), | ||
MESSAGE_UNAUTHORIZED("유효하지 않은 토큰"), | ||
; | ||
|
||
private final String message; | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/com/soptie/server/auth/message/ResponseMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.soptie.server.auth.message; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
@Getter | ||
public enum ResponseMessage { | ||
|
||
SUCCESS_SIGNIN("소셜로그인 성공"); | ||
|
||
private final String message; | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/soptie/server/auth/service/AuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.soptie.server.auth.service; | ||
|
||
import com.soptie.server.auth.dto.SignInRequest; | ||
import com.soptie.server.auth.dto.SignInResponse; | ||
|
||
public interface AuthService { | ||
|
||
SignInResponse signIn(String socialAccessToken, SignInRequest request); | ||
} |
Oops, something went wrong.