-
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.
feat: (#1) Jwt 필터 추가 및 Secuirty 필터 설정
- Jwt 생성을 위한 Secret Key 등록 - /와 같은 health URI에 대해서는 Allow - /login/** 에는 Login 필터만 적용 - /member/** 경우에는 Jwt 필터 적용
- Loading branch information
Showing
14 changed files
with
303 additions
and
10 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
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
21 changes: 21 additions & 0 deletions
21
src/main/java/com/tune/server/controller/MemberController.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,21 @@ | ||
package com.tune.server.controller; | ||
|
||
import com.tune.server.domain.Member; | ||
import com.tune.server.dto.response.MemberResponse; | ||
import com.tune.server.service.member.MemberService; | ||
import lombok.AllArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import springfox.documentation.annotations.ApiIgnore; | ||
|
||
@RestController | ||
@AllArgsConstructor | ||
public class MemberController { | ||
private final MemberService memberService; | ||
@GetMapping("/member") | ||
public ResponseEntity<MemberResponse> getMember(@ApiIgnore Authentication authentication) { | ||
return ResponseEntity.ok(MemberResponse.of((Member) authentication.getPrincipal())); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/com/tune/server/dto/response/MemberResponse.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,21 @@ | ||
package com.tune.server.dto.response; | ||
|
||
import com.tune.server.domain.Member; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.ToString; | ||
|
||
@Getter | ||
@Builder | ||
@ToString | ||
public class MemberResponse { | ||
private Long id; | ||
private String name; | ||
|
||
public static MemberResponse of(Member member) { | ||
return MemberResponse.builder() | ||
.id(member.getId()) | ||
.name(member.getName()) | ||
.build(); | ||
} | ||
} |
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
10 changes: 10 additions & 0 deletions
10
src/main/java/com/tune/server/exceptions/login/TokenExpiredException.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.tune.server.exceptions.login; | ||
|
||
import com.tune.server.exceptions.ErrorResponse; | ||
import org.springframework.http.HttpStatus; | ||
|
||
public class TokenExpiredException extends ErrorResponse { | ||
public TokenExpiredException(String message) { | ||
super(message, HttpStatus.UNAUTHORIZED.value()); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/tune/server/exceptions/login/TokenNotFoundException.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.tune.server.exceptions.login; | ||
|
||
import com.tune.server.exceptions.ErrorResponse; | ||
import org.springframework.http.HttpStatus; | ||
|
||
public class TokenNotFoundException extends ErrorResponse { | ||
public TokenNotFoundException(String message) { | ||
super(message, HttpStatus.FORBIDDEN.value()); | ||
} | ||
} |
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
60 changes: 60 additions & 0 deletions
60
src/main/java/com/tune/server/filter/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,60 @@ | ||
package com.tune.server.filter; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.tune.server.domain.Member; | ||
import com.tune.server.exceptions.login.InvalidTokenException; | ||
import com.tune.server.exceptions.login.TokenExpiredException; | ||
import com.tune.server.exceptions.login.TokenNotFoundException; | ||
import com.tune.server.service.member.MemberService; | ||
import com.tune.server.util.JwtUtil; | ||
import lombok.AllArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.authority.SimpleGrantedAuthority; | ||
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.ServletException; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
import java.io.IOException; | ||
import java.sql.Date; | ||
import java.time.LocalDateTime; | ||
import java.time.ZoneId; | ||
import java.util.List; | ||
|
||
@AllArgsConstructor | ||
@Slf4j | ||
public class JwtAuthenticationFilter extends OncePerRequestFilter { | ||
private ObjectMapper objectMapper; | ||
private MemberService memberService; | ||
@Override | ||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { | ||
final String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION); | ||
|
||
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) | ||
throw new TokenNotFoundException("JWT Token does not begin with Bearer String with URL : " + request.getRequestURI()); | ||
|
||
|
||
String token = authorizationHeader.split(" ")[1]; | ||
if (!JwtUtil.isValidJwt(token)) | ||
throw new InvalidTokenException("JWT Token is not valid with Jwt : " + token); | ||
|
||
if (JwtUtil.isExpired(token, Date.from(LocalDateTime.now().atZone(ZoneId.of("Asia/Seoul")).toInstant()))) | ||
throw new TokenExpiredException("JWT Token is expired"); | ||
|
||
// Member 식별 | ||
Member member = JwtUtil.getMemberFromJwt(token, objectMapper); | ||
|
||
// 권한 부여 | ||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(member, null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); | ||
|
||
// UserDetail을 통해 인증된 사용자 정보를 SecurityContext에 저장 | ||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); | ||
SecurityContextHolder.getContext().setAuthentication(authenticationToken); | ||
filterChain.doFilter(request, response); | ||
} | ||
} |
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
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 |
---|---|---|
@@ -1,20 +1,86 @@ | ||
package com.tune.server.util; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.tune.server.domain.Member; | ||
import io.jsonwebtoken.Jwts; | ||
import io.jsonwebtoken.SignatureAlgorithm; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.time.LocalDateTime; | ||
import java.time.ZoneId; | ||
import java.util.Date; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.UUID; | ||
|
||
@Component | ||
public class JwtUtil { | ||
|
||
// JWT_SECRET_KEY is set in application.yml | ||
public static String JWT_SECRET_KEY; | ||
|
||
// refresh token expires in 6 months | ||
public static final int REFRESH_TOKEN_EXPIRES_MONTH = 6; | ||
|
||
// access token expires in 12 hours | ||
public static final int ACCESS_TOKEN_EXPIRE_MINUTE = 12 * 60; | ||
|
||
@Value("${external.jwt.secret}") | ||
public void setKey(String key) { | ||
JWT_SECRET_KEY = key; | ||
} | ||
|
||
public static Member getMemberFromJwt(String token, ObjectMapper objectMapper) { | ||
Map<String, Object> claims = Jwts.parserBuilder() | ||
.setSigningKey(JWT_SECRET_KEY) | ||
.build() | ||
.parseClaimsJws(token) | ||
.getBody(); | ||
|
||
return objectMapper.convertValue(claims, Member.class); | ||
} | ||
|
||
public static String generateJwt(Member member) { | ||
return "jwt"; | ||
Date now = Date.from(LocalDateTime.now().atZone(ZoneId.of("Asia/Seoul")).toInstant()); | ||
Date accessTokenExpiredDate = Date.from(LocalDateTime.now().plusMinutes(ACCESS_TOKEN_EXPIRE_MINUTE).atZone(ZoneId.of("Asia/Seoul")).toInstant()); | ||
|
||
Map<String, Object> claims = new HashMap<>(); | ||
claims.put("id", member.getId()); | ||
claims.put("name", member.getName()); | ||
|
||
return Jwts.builder() | ||
.setClaims(claims) | ||
.setIssuedAt(now) | ||
.setExpiration(accessTokenExpiredDate) | ||
.signWith(SignatureAlgorithm.HS256, JWT_SECRET_KEY) | ||
.compact(); | ||
} | ||
|
||
public static boolean isValidJwt(String token) { | ||
try { | ||
Jwts.parserBuilder() | ||
.setSigningKey(JWT_SECRET_KEY) | ||
.build() | ||
.parseClaimsJws(token); | ||
return true; | ||
} catch (Exception e) { | ||
return false; | ||
} | ||
} | ||
|
||
public static boolean isExpired(String token, Date date) { | ||
Date expiredDate = Jwts.parserBuilder() | ||
.setSigningKey(JWT_SECRET_KEY) | ||
.build() | ||
.parseClaimsJws(token) | ||
.getBody() | ||
.getExpiration(); | ||
|
||
return expiredDate.before(date); | ||
} | ||
|
||
public static String generateRefreshToken() { | ||
return "refreshToken"; | ||
return UUID.randomUUID().toString().replace("-", ""); | ||
} | ||
} |
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 |
---|---|---|
|
@@ -29,3 +29,7 @@ spring: | |
enabled: always | ||
server: | ||
port: 8081 | ||
|
||
external: | ||
jwt: | ||
secret: ${JWT_SECRET} |
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
Oops, something went wrong.