Skip to content

Commit

Permalink
Merge pull request #144 from Soongsil-CoffeeChat/feat/#142
Browse files Browse the repository at this point in the history
feat: mobile 전용 accessToken 발급 api 구현
  • Loading branch information
KimKyoHwee authored Sep 22, 2024
2 parents 2414b82 + f0ff9ff commit 8b48a3b
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.successHandler(customSuccessHandler))
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 모든 OPTIONS 요청에 대해 인증을 요구하지 않음
.requestMatchers("/health-check", "/", "/reissue", "/security-check").permitAll()
.requestMatchers("/health-check", "/", "/auth/reissue/**", "/security-check").permitAll()
.requestMatchers("/api/v2/users/**", "/auth/**").hasRole("USER")
.requestMatchers("/api/v2/possibleDates/**").hasAnyRole("MENTOR", "MENTEE")
.requestMatchers("/api/v2/mentors/**").hasAnyRole("MENTOR", "MENTEE")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
return;
}
String path = request.getRequestURI();
if (path.startsWith("/health-check") || path.startsWith("/security-check") || path.startsWith("/reissue")) {
if (path.startsWith("/health-check") || path.startsWith("/security-check") || path.startsWith("/auth/reissue")) {
System.out.println("jwt필터 통과로직");
filterChain.doFilter(request, response);
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,53 @@
package com.soongsil.CoffeeChat.controller;

import com.soongsil.CoffeeChat.controller.handler.ApiResponseGenerator;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.soongsil.CoffeeChat.config.jwt.JWTUtil;
import com.soongsil.CoffeeChat.controller.handler.ApiResponseGenerator;
import com.soongsil.CoffeeChat.service.CustomOAuth2UserService;
import com.soongsil.CoffeeChat.service.RefreshTokenService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;

@RestController //RestController=Controller+ResponseBody
@RequestMapping("/auth")
@Tag(name = "REFRESHTOKEN", description = "리프레쉬 토큰 관련 api")
@RequiredArgsConstructor
public class RefreshTokenController { //Refresh토큰으로 Access토큰 발급 및 2차회원가입 컨트롤러
private final JWTUtil jwtUtil;
private final RefreshTokenService refreshTokenService;

public RefreshTokenController(JWTUtil jwtUtil, RefreshTokenService refreshTokenService) {
this.jwtUtil = jwtUtil;
this.refreshTokenService = refreshTokenService;
}
private final CustomOAuth2UserService oAuth2UserService;

@PostMapping("/reissue")
@Operation(summary = "리프레쉬 토큰으로 액세스 토큰 reissue")
@ApiResponse(responseCode = "200", description = "헤더 : access, refresh, loginStatus")
public ResponseEntity<ApiResponseGenerator<String>> reissue(HttpServletRequest request, HttpServletResponse response) {
public ResponseEntity<ApiResponseGenerator<String>> reissue(HttpServletRequest request,
HttpServletResponse response) {
return ResponseEntity.ok().body(
ApiResponseGenerator.onSuccessOK(
refreshTokenService.reissueByRefreshToken(request, response)
)
);
}

@PostMapping("/reissue/mobile")
@Operation(summary = "리소스 서버에서 받은 accessToken으로 서비스 accessToken 발급")
@ApiResponse(responseCode = "200", description = "유효한 google accessToken으로 요청시 body로 ROLE_USER 토큰 반환")
public ResponseEntity<ApiResponseGenerator<String>> issueAccessToken(@RequestParam String accessToken) {
return ResponseEntity.ok().body(
ApiResponseGenerator.onSuccessOK(
refreshTokenService.reissueByRefreshToken(request, response)
)
ApiResponseGenerator.onSuccessOK(
oAuth2UserService.verifyGoogleToken(accessToken)
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public enum RefreshErrorCode {
REFRESH_NOT_FOUND(HttpStatus.NOT_FOUND, "REFRESH_404", "refresh 토큰이 들어오지 않았습니다."),
REFRESH_EXPIRED(HttpStatus.FORBIDDEN, "REFRESH_403", "refresh 토큰이 만료되었습니다."),
REFRESH_NOT_MATCHED(HttpStatus.UNAUTHORIZED, "REFRESH_401", "저장되지 않은 refresh 토큰입니다."),
REFRESH_BAD_REQUEST(HttpStatus.BAD_REQUEST, "REFRESH_400", "refresh 토큰이 아닌 다른 종류의 토큰이 들어왔습니다.");
REFRESH_BAD_REQUEST(HttpStatus.BAD_REQUEST, "REFRESH_400", "refresh 토큰이 아닌 다른 종류의 토큰이 들어왔습니다."),
INVALID_TOKEN(HttpStatus.BAD_REQUEST, "GOOGLE_ACCESS_400", "유효하지 않은 Google accessToken입니다.");

private final HttpStatusCode httpStatusCode;
private final String errorCode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
package com.soongsil.CoffeeChat.service;

import com.soongsil.CoffeeChat.controller.exception.CustomException;
import com.soongsil.CoffeeChat.dto.Oauth.*;
import static com.soongsil.CoffeeChat.controller.exception.enums.RefreshErrorCode.*;

import java.util.Map;

import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.soongsil.CoffeeChat.config.jwt.JWTUtil;
import com.soongsil.CoffeeChat.controller.exception.CustomException;
import com.soongsil.CoffeeChat.dto.Oauth.CustomOAuth2User;
import com.soongsil.CoffeeChat.dto.Oauth.GoogleResponse;
import com.soongsil.CoffeeChat.dto.Oauth.KakaoResponse;
import com.soongsil.CoffeeChat.dto.Oauth.NaverResponse;
import com.soongsil.CoffeeChat.dto.Oauth.OAuth2Response;
import com.soongsil.CoffeeChat.dto.Oauth.UserDTO;
import com.soongsil.CoffeeChat.entity.User;
import com.soongsil.CoffeeChat.repository.User.UserRepository;

import jakarta.transaction.Transactional;

import static com.soongsil.CoffeeChat.controller.exception.enums.UserErrorCode.USER_NOT_FOUND;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
private final UserRepository userRepository;

public CustomOAuth2UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
private final JWTUtil jwtUtil;

private User findUserByUsername(String username){
private static final String GOOGLE_TOKEN_INFO_URL = "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=";

private User findUserByUsername(String username) {
return userRepository.findByUsername(username)
.orElse(null);
.orElse(null);
}

//리소스 서버에서 제공되는 유저정보 가져오기
Expand Down Expand Up @@ -85,4 +96,24 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
}

}

public String verifyGoogleToken(String accessToken) {
RestTemplate restTemplate = new RestTemplate();
String url = GOOGLE_TOKEN_INFO_URL + accessToken;
Map<String, Object> tokenInfo = restTemplate.getForObject(url, Map.class);
if (tokenInfo != null && tokenInfo.containsKey("sub")) {
String googleId = (String)tokenInfo.get("sub");
return jwtUtil.createJwt(
"access",
googleId,
"ROLE_USER",
180000L
);
} else {
throw new CustomException(
INVALID_TOKEN.getHttpStatusCode(),
INVALID_TOKEN.getErrorMessage()
);
}
}
}

0 comments on commit 8b48a3b

Please sign in to comment.