From 90cc784547ccd89a1418381c5972b33c532989a9 Mon Sep 17 00:00:00 2001 From: SangHyun Jung Date: Thu, 21 Nov 2024 01:03:33 +0900 Subject: [PATCH 1/4] =?UTF-8?q?11.21(=EB=AA=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kuit/kuit4serverauth/config/WebConfig.java | 3 ++- .../kuit/kuit4serverauth/controller/AuthController.java | 7 ++++++- .../kuit/kuit4serverauth/controller/UserController.java | 2 ++ .../kuit/kuit4serverauth/interceptor/AuthInterceptor.java | 4 ++++ .../java/com/kuit/kuit4serverauth/service/JwtUtil.java | 6 ++++-- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/kuit/kuit4serverauth/config/WebConfig.java b/src/main/java/com/kuit/kuit4serverauth/config/WebConfig.java index a0b47b4..6f86233 100644 --- a/src/main/java/com/kuit/kuit4serverauth/config/WebConfig.java +++ b/src/main/java/com/kuit/kuit4serverauth/config/WebConfig.java @@ -7,7 +7,7 @@ @Configuration public class WebConfig implements WebMvcConfigurer { - private final AuthInterceptor authInterceptor; + private final AuthInterceptor authInterceptor; // 등록 해야 함 public WebConfig(AuthInterceptor authInterceptor) { this.authInterceptor = authInterceptor; @@ -16,5 +16,6 @@ public WebConfig(AuthInterceptor authInterceptor) { @Override public void addInterceptors(InterceptorRegistry registry) { // TODO /profile, /admin 앞에 붙이기 + } } diff --git a/src/main/java/com/kuit/kuit4serverauth/controller/AuthController.java b/src/main/java/com/kuit/kuit4serverauth/controller/AuthController.java index e8f7e24..9e5e36f 100644 --- a/src/main/java/com/kuit/kuit4serverauth/controller/AuthController.java +++ b/src/main/java/com/kuit/kuit4serverauth/controller/AuthController.java @@ -24,19 +24,24 @@ public AuthController(UserRepository userRepository, JwtUtil jwtUtil) { this.jwtUtil = jwtUtil; } + // @RequestBody 부분 DTO로 감싸기 + // API를 통해 JWT 토큰을 발급 @PostMapping("/login") public ResponseEntity> login(@RequestBody Map credentials) { String username = credentials.get("username"); String password = credentials.get("password"); User user = userRepository.findByUsername(username); + // 유저가 있는지, 비밀번호가 맞는지 if (user == null || !user.getPassword().equals(password)) { throw new CustomException(ErrorCode.INVALID_USERNAME_OR_PASSWORD); } + // Map을 DTO로 감싸는게 좋다 + // JWT Token 생성 String token = jwtUtil.generateToken(user.getUsername(), user.getRole()); Map response = new HashMap<>(); - response.put("token", token); + response.put("token", token); // 토큰을 응답으로 보낸다 return ResponseEntity.ok(response); } } diff --git a/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java b/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java index 18cb7af..78a3169 100644 --- a/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java +++ b/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java @@ -9,12 +9,14 @@ @RestController public class UserController { + // API를 인증된 사용자만 접근 가능하도록 @GetMapping("/profile") public ResponseEntity getProfile(HttpServletRequest request) { // TODO : 로그인 한 사용자면 username 이용해 "Hello, {username}" 반환하기 return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized"); } + // API에 관리자 권하이 있는 사용자만 접근 가능하도록 @GetMapping("/admin") public ResponseEntity getAdmin(HttpServletRequest request) { // TODO: role이 admin이면 "Hello, admin" 반환하기 diff --git a/src/main/java/com/kuit/kuit4serverauth/interceptor/AuthInterceptor.java b/src/main/java/com/kuit/kuit4serverauth/interceptor/AuthInterceptor.java index 7b48ce8..b3bfe49 100644 --- a/src/main/java/com/kuit/kuit4serverauth/interceptor/AuthInterceptor.java +++ b/src/main/java/com/kuit/kuit4serverauth/interceptor/AuthInterceptor.java @@ -14,9 +14,11 @@ public class AuthInterceptor implements HandlerInterceptor { private final JwtUtil jwtUtil; public AuthInterceptor(JwtUtil jwtUtil) { + this.jwtUtil = jwtUtil; } + @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String authHeader = request.getHeader("Authorization"); @@ -25,8 +27,10 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons Claims claims = jwtUtil.validateToken(token); request.setAttribute("username", claims.getSubject()); request.setAttribute("role", claims.get("role")); + // userName / role을 request에 담아서 controller에 보냄 return true; } + throw new CustomException(ErrorCode.MISSING_AUTH_HEADER); } } diff --git a/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java b/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java index ead240e..ae8d0f4 100644 --- a/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java +++ b/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java @@ -12,7 +12,8 @@ @Component public class JwtUtil { private final String secret = "mysecretkey"; - private final long expirationMs = 3600000; // 1 hour + private final long expirationMs = 3600000; // 1 hour, 만료시간 + // yml 파일에서 환경변수 설정으로 가져오기 -> 이걸 이용해서 수정 public String generateToken(String username, String role) { return Jwts.builder() @@ -24,10 +25,11 @@ public String generateToken(String username, String role) { .compact(); } + // 가져온 토큰을 파싱 public Claims validateToken(String token) { try { return Jwts.parser() - .setSigningKey(secret) + .setSigningKey(secret) // 발급 한 토큰이 맞는지 검증 .parseClaimsJws(token) .getBody(); } catch (Exception e) { From 67e1e4ff3aeba99d83345856fc02865f35f57ece Mon Sep 17 00:00:00 2001 From: SangHyun Jung Date: Fri, 22 Nov 2024 22:48:03 +0900 Subject: [PATCH 2/4] =?UTF-8?q?11.22(=EA=B8=88)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/UserController.java | 34 +++++++++++++++++-- .../interceptor/AuthInterceptor.java | 7 ++-- .../kuit/kuit4serverauth/service/JwtUtil.java | 12 +++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java b/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java index 78a3169..eaa5d32 100644 --- a/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java +++ b/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java @@ -1,5 +1,8 @@ package com.kuit.kuit4serverauth.controller; +import com.kuit.kuit4serverauth.exception.CustomException; +import com.kuit.kuit4serverauth.exception.ErrorCode; +import com.kuit.kuit4serverauth.service.JwtUtil; import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -9,17 +12,42 @@ @RestController public class UserController { + private final JwtUtil jwtUtil; + + public UserController(JwtUtil jwtUtil) { + this.jwtUtil = jwtUtil; + } + // API를 인증된 사용자만 접근 가능하도록 @GetMapping("/profile") public ResponseEntity getProfile(HttpServletRequest request) { // TODO : 로그인 한 사용자면 username 이용해 "Hello, {username}" 반환하기 - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized"); + String token = request.getHeader("Authorization"); + + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized"); + } + + String username = jwtUtil.getUsernameFromToken(token); + return ResponseEntity.ok("Hello, " + username); } - // API에 관리자 권하이 있는 사용자만 접근 가능하도록 + // API에 관리자 권한 (ROLE_ADMIN) 있는 사용자만 접근 가능하도록 @GetMapping("/admin") public ResponseEntity getAdmin(HttpServletRequest request) { // TODO: role이 admin이면 "Hello, admin" 반환하기 - return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Forbidden"); + String token = request.getHeader("Authorization"); + + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized"); + } + + String role = jwtUtil.getRoleFromToken(token); + if (! "ROLE_ADMIN".equals(role)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Forbidden user"); + } + + return ResponseEntity.ok("Hello, admin user"); + } } diff --git a/src/main/java/com/kuit/kuit4serverauth/interceptor/AuthInterceptor.java b/src/main/java/com/kuit/kuit4serverauth/interceptor/AuthInterceptor.java index b3bfe49..0e3b581 100644 --- a/src/main/java/com/kuit/kuit4serverauth/interceptor/AuthInterceptor.java +++ b/src/main/java/com/kuit/kuit4serverauth/interceptor/AuthInterceptor.java @@ -9,24 +9,27 @@ import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; +// HTTP 요청 처리 전 특정 검증 로직 수행 +// JWT 검증 + 사용자 정보를 요청 속성에 추가 @Component public class AuthInterceptor implements HandlerInterceptor { private final JwtUtil jwtUtil; public AuthInterceptor(JwtUtil jwtUtil) { - this.jwtUtil = jwtUtil; } - @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String authHeader = request.getHeader("Authorization"); + if (authHeader != null && authHeader.startsWith("Bearer ")) { String token = authHeader.substring(7); Claims claims = jwtUtil.validateToken(token); + request.setAttribute("username", claims.getSubject()); request.setAttribute("role", claims.get("role")); + // userName / role을 request에 담아서 controller에 보냄 return true; } diff --git a/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java b/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java index ae8d0f4..70f2169 100644 --- a/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java +++ b/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java @@ -9,6 +9,7 @@ import java.util.Date; +// JWT를 생성하고 검증 @Component public class JwtUtil { private final String secret = "mysecretkey"; @@ -36,4 +37,15 @@ public Claims validateToken(String token) { throw new CustomException(ErrorCode.INVALID_TOKEN); } } + + // Claims에서 username 추출 + public String getUsernameFromToken(String token) { + return validateToken(token).getSubject(); + } + + // Claims에서 role추출 + public String getRoleFromToken(String token) { + return validateToken(token).get("role").toString(); + } + } \ No newline at end of file From 0cee7284671bb5672fe4ba132c6e9b412c1f78c5 Mon Sep 17 00:00:00 2001 From: SangHyun Jung Date: Fri, 22 Nov 2024 23:55:52 +0900 Subject: [PATCH 3/4] =?UTF-8?q?mysecretkey=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=ED=95=98=EB=8D=98=20=EC=A4=91..?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kuit4serverauth/controller/AuthController.java | 3 +++ .../kuit4serverauth/controller/UserController.java | 8 ++++---- .../java/com/kuit/kuit4serverauth/service/JwtUtil.java | 10 +++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/kuit/kuit4serverauth/controller/AuthController.java b/src/main/java/com/kuit/kuit4serverauth/controller/AuthController.java index 9e5e36f..29ab2e5 100644 --- a/src/main/java/com/kuit/kuit4serverauth/controller/AuthController.java +++ b/src/main/java/com/kuit/kuit4serverauth/controller/AuthController.java @@ -14,6 +14,7 @@ import java.util.HashMap; import java.util.Map; +// RestController : JSON형식의 응답반환 @RestController public class AuthController { private final UserRepository userRepository; @@ -40,6 +41,8 @@ public ResponseEntity> login(@RequestBody Map response = new HashMap<>(); response.put("token", token); // 토큰을 응답으로 보낸다 return ResponseEntity.ok(response); diff --git a/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java b/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java index eaa5d32..2c9c283 100644 --- a/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java +++ b/src/main/java/com/kuit/kuit4serverauth/controller/UserController.java @@ -25,7 +25,7 @@ public ResponseEntity getProfile(HttpServletRequest request) { String token = request.getHeader("Authorization"); if (token == null) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized"); + throw new CustomException(ErrorCode.INVALID_TOKEN); } String username = jwtUtil.getUsernameFromToken(token); @@ -39,15 +39,15 @@ public ResponseEntity getAdmin(HttpServletRequest request) { String token = request.getHeader("Authorization"); if (token == null) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized"); + throw new CustomException(ErrorCode.INVALID_TOKEN); } String role = jwtUtil.getRoleFromToken(token); if (! "ROLE_ADMIN".equals(role)) { - return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Forbidden user"); + throw new CustomException(ErrorCode.FORBIDDEN_ACCESS); } - return ResponseEntity.ok("Hello, admin user"); + return ResponseEntity.ok("Hello, admin"); } } diff --git a/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java b/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java index 70f2169..db7f277 100644 --- a/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java +++ b/src/main/java/com/kuit/kuit4serverauth/service/JwtUtil.java @@ -5,14 +5,18 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; import org.springframework.stereotype.Component; +import java.security.Key; import java.util.Date; // JWT를 생성하고 검증 @Component public class JwtUtil { - private final String secret = "mysecretkey"; + // todo + // private final String secret = "mysecretkey"; + private final Key secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256); // 안전한 비밀 키 생성 private final long expirationMs = 3600000; // 1 hour, 만료시간 // yml 파일에서 환경변수 설정으로 가져오기 -> 이걸 이용해서 수정 @@ -22,7 +26,7 @@ public String generateToken(String username, String role) { .claim("role", role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + expirationMs)) - .signWith(SignatureAlgorithm.HS256, secret) + .signWith(secretKey) .compact(); } @@ -30,7 +34,7 @@ public String generateToken(String username, String role) { public Claims validateToken(String token) { try { return Jwts.parser() - .setSigningKey(secret) // 발급 한 토큰이 맞는지 검증 + .setSigningKey(secretKey) // 발급 한 토큰이 맞는지 검증 .parseClaimsJws(token) .getBody(); } catch (Exception e) { From 228513a2ce4f9e99419da08430d9fe0c374ee061 Mon Sep 17 00:00:00 2001 From: SangHyun Jung Date: Sat, 23 Nov 2024 13:18:37 +0900 Subject: [PATCH 4/4] =?UTF-8?q?11.23(=ED=86=A0)=201.=20addInterceptors=20?= =?UTF-8?q?=EB=A9=94=EC=86=8C=EB=93=9C,=20/profile,=20/admin=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=B6=94=EA=B0=80=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (secrekey 및 만료시간 문제 부분 미해결) --- .../java/com/kuit/kuit4serverauth/config/WebConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/kuit/kuit4serverauth/config/WebConfig.java b/src/main/java/com/kuit/kuit4serverauth/config/WebConfig.java index 6f86233..5229bdf 100644 --- a/src/main/java/com/kuit/kuit4serverauth/config/WebConfig.java +++ b/src/main/java/com/kuit/kuit4serverauth/config/WebConfig.java @@ -15,7 +15,7 @@ public WebConfig(AuthInterceptor authInterceptor) { @Override public void addInterceptors(InterceptorRegistry registry) { - // TODO /profile, /admin 앞에 붙이기 - + // /profile, /admin 경로에서 동작하도록 경로제한 + registry.addInterceptor(authInterceptor).addPathPatterns("/profile", "/admin"); } -} +} \ No newline at end of file