Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 네이버 auth #20

Merged
merged 16 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions .github/workflows/google java format.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
name: google-java-format

on: [ push, pull_request ]

jobs:
formatting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Print Selected Files
- name: Set BRANCH_NAME
run: |
BRANCH_NAME=$(echo ${{ github.ref }} | sed 's#refs/heads/##')
echo "GitHub Workspace: $GITHUB_WORKSPACE"
BRANCH_NAME=$(echo "${{ github.ref }}" | awk -F'/' '{print $NF}')
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
echo "GitHub Ref: ${{ github.ref }}"
echo "Branch Name: $BRANCH_NAME"
echo "Setting FILE_PATTERN variable"
echo "FILE_PATTERN=${GITHUB_WORKSPACE}/src/main/java/com/haemil/backend/${BRANCH_NAME}/*" >> $GITHUB_ENV

echo "check.... "
ls -al
echo "check.... "
pwd
cd src/main/java/com/haemil/backend/auth
FILE_PATTERN="/home/runner/work/haemil-backend/haemil-backend/src/main/java/com/haemil/backend/${BRANCH_NAME}/*"
echo "FILE_PATTERN Name: $FILE_PATTERN"
if [[ -d "$FILE_PATTERN" ]]; then
echo "Setting FILE_PATTERN variable"
echo "FILE_PATTERN=$FILE_PATTERN" >> $GITHUB_ENV
else
echo "Directory does not exist for the given branch."
fi

- name: Check formatting
if: env.FILE_PATTERN != ''
uses: axel-op/googlejavaformat-action@v3
with:
args: "--replace"
github-token: ${{ secrets.GITHUB_TOKEN }}
skip-commit: true
files: "${{ env.FILE_PATTERN }}"

- name: Print diffs
run: git --no-pager diff --exit-code

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.haemil.backend.auth.dto.RespLoginDto;
import com.haemil.backend.auth.dto.SuccessDto;
import com.haemil.backend.auth.dto.kakao.KakaoLoginParams;
import com.haemil.backend.auth.dto.naver.NaverLoginParams;
import com.haemil.backend.auth.service.AuthService;
import com.haemil.backend.global.config.BaseException;
import com.haemil.backend.global.config.BaseResponse;
Expand All @@ -30,11 +31,27 @@ public class AuthController {
@Value("${jwt.cookie-period}")
private long CookiePeriod;

// 카카오 로그인
@PostMapping("/kakao")
public ResponseEntity<BaseResponse> loginKakao(@RequestParam Boolean isGuardian, @RequestBody KakaoLoginParams params) {
public ResponseEntity<BaseResponse> loginKakao(@RequestBody KakaoLoginParams params) {
try {
log.debug("isGuardian = {}", isGuardian);
RespLoginDto respLoginDto = authService.login(params, isGuardian);
RespLoginDto respLoginDto = authService.login(params);

HttpHeaders headers = respLoginDto.getHeaders();
LoginDto loginDto = respLoginDto.getLoginDto();

return ResponseEntity.ok().headers(headers).body(new BaseResponse<>(loginDto));
} catch (BaseException e){
return new BaseResponse<>(e.getStatus()).convert();
}
}

// 네이버 로그인
@PostMapping("/naver")
public ResponseEntity<BaseResponse> loginNaver(@RequestBody NaverLoginParams params) {
try {

RespLoginDto respLoginDto = authService.login(params);

HttpHeaders headers = respLoginDto.getHeaders();
LoginDto loginDto = respLoginDto.getLoginDto();
Expand All @@ -57,7 +74,6 @@ public ResponseEntity<?> reissue(@CookieValue(name = "refresh-token") String req
// RT 저장
ResponseCookie responseCookie = ResponseCookie.from("refresh-token", reissuedTokenDto.getRefreshToken())
.maxAge(CookiePeriod)
// .domain(".photohere.co.kr")
.path("/")
.sameSite("None")
.httpOnly(true)
Expand Down Expand Up @@ -90,16 +106,6 @@ public ResponseEntity<?> reissue(@CookieValue(name = "refresh-token") String req
}
}

// temp mapping - find cookie

@RequestMapping("/getCookie1")
public ResponseEntity<BaseResponse<String>> getCookie1(@CookieValue String useremail, @CookieValue("useremail") String umail) {
System.out.println(umail);
return ResponseEntity.ok().body(new BaseResponse<>("test."));
}

// --

// 로그아웃
@PostMapping("/logout")
public ResponseEntity<?> logout(@RequestHeader("Authorization") String requestAccessToken) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.haemil.backend.auth.dto.naver;

import com.haemil.backend.global.security.oauth.OAuthApiClient;
import com.haemil.backend.global.security.oauth.OAuthInfoResponse;
import com.haemil.backend.global.security.oauth.OAuthLoginParams;
import com.haemil.backend.global.security.oauth.OAuthProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

@Component
@RequiredArgsConstructor
@Slf4j
public class NaverApiClient implements OAuthApiClient {

private static final String GRANT_TYPE = "authorization_code";

@Value("${oauth.naver.url.auth}")
private String authUrl;

@Value("${oauth.naver.url.api}")
private String apiUrl;

@Value("${oauth.naver.client-id}")
private String clientId;

@Value("${oauth.naver.secret}")
private String clientSecret;

private final RestTemplate restTemplate;

@Override
public OAuthProvider oAuthProvider() {
return OAuthProvider.NAVER;
}

@Override
public String requestAccessToken(OAuthLoginParams params) {
String url = authUrl + "/oauth2.0/token";

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

MultiValueMap<String, String> body = params.makeBody();
body.add("grant_type", GRANT_TYPE);
body.add("client_id", clientId);
body.add("client_secret", clientSecret);

HttpEntity<?> request = new HttpEntity<>(body, httpHeaders);

NaverTokens response = restTemplate.postForObject(url, request, NaverTokens.class);

assert response != null;
return response.getAccessToken();
}

@Override
public OAuthInfoResponse requestOauthInfo(String accessToken) {
String url = apiUrl + "/v1/nid/me";

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
httpHeaders.set("Authorization", "Bearer " + accessToken);

MultiValueMap<String, String> body = new LinkedMultiValueMap<>();

HttpEntity<?> request = new HttpEntity<>(body, httpHeaders);

return restTemplate.postForObject(url, request, NaverInfoResponse.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.haemil.backend.auth.dto.naver;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.haemil.backend.global.security.oauth.OAuthInfoResponse;
import com.haemil.backend.global.security.oauth.OAuthProvider;
import lombok.Getter;

@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
public class NaverInfoResponse implements OAuthInfoResponse {

@JsonProperty("response")
private Response response;

@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
static class Response {
private String email;
private String nickname;
}

@Override
public String getEmail() {
return response.email;
}

@Override
public String getNickname() {
return response.nickname;
}

@Override
public String getProfileImageUrl() {
return "test";
}

@Override
public OAuthProvider getOAuthProvider() {
return OAuthProvider.NAVER;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.haemil.backend.auth.dto.naver;

import com.haemil.backend.global.security.oauth.OAuthLoginParams;
import com.haemil.backend.global.security.oauth.OAuthProvider;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

@Getter
@NoArgsConstructor
public class NaverLoginParams implements OAuthLoginParams {
private String authorizationCode;
private String state;

@Override
public OAuthProvider oAuthProvider() {
return OAuthProvider.NAVER;
}

@Override
public MultiValueMap<String, String> makeBody() {
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("code", authorizationCode);
body.add("state", state);
return body;
}
}
22 changes: 22 additions & 0 deletions src/main/java/com/haemil/backend/auth/dto/naver/NaverTokens.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.haemil.backend.auth.dto.naver;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class NaverTokens {

@JsonProperty("access_token")
private String accessToken;

@JsonProperty("refresh_token")
private String refreshToken;

@JsonProperty("token_type")
private String tokenType;

@JsonProperty("expires_in")
private String expiresIn;
}
34 changes: 6 additions & 28 deletions src/main/java/com/haemil/backend/auth/service/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ public class AuthService {
private long CookiePeriod;

// 로그인: 인증 정보 저장 및 비어 토큰 발급
public RespLoginDto login(OAuthLoginParams params, Boolean isGuardian) throws BaseException {
public RespLoginDto login(OAuthLoginParams params) throws BaseException {

OAuthInfoResponse oAuthInfoResponse = requestOAuthInfoService.request(params);
Long userId = findOrCreateUser(oAuthInfoResponse, isGuardian);
Long userId = findOrCreateUser(oAuthInfoResponse);
AuthTokens token = createToken(userId, oAuthInfoResponse);

User user = userRepository.findById(userId).orElseThrow(() -> new BaseException(ResponseStatus.NO_USER));
Expand Down Expand Up @@ -141,12 +141,8 @@ public void logout(String requestAccessTokenInHeader) throws BaseException {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String principal = getPrincipal(requestAccessToken);

log.info("AT input: {}", requestAccessToken);
log.info("principal: {}", principal);

// Redis에 저장되어 있는 RT 삭제
String refreshTokenInRedis = redisService.getValues("RT(" + SERVER + "):" + principal);
log.info("refreshTokenInRedis = {}", refreshTokenInRedis);
if (refreshTokenInRedis == null) {
throw new BaseException(ResponseStatus.INVALID_AUTH);
} else {
Expand All @@ -162,23 +158,6 @@ public void logout(String requestAccessTokenInHeader) throws BaseException {
} catch (BaseException e) {
throw new BaseException(ResponseStatus.INVALID_AUTH);
}

// JWT 토큰 검증
// try {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// Long userId = Long.parseLong(authentication.getName());
// log.info("authentication = {}", authentication);
// log.info("userId = {}", userId);
//
// // validate 진행 필요.
// if (!principal.equals(1)) {
// throw new BaseException(ResponseStatus.INVALID_AUTH);
// }
// } catch (JwtException e) {
// throw new BaseException(ResponseStatus.INVALID_AUTH);
// }


}

/* -- 그 외 메서드 -- */
Expand Down Expand Up @@ -209,7 +188,7 @@ public ResponseCookie saveHttpCookie(AuthTokens token) {
// RT 저장
ResponseCookie httpCookie = ResponseCookie.from("refresh-token", token.getRefreshToken())
.maxAge(CookiePeriod)
.domain("api.photohere.co.kr")
.domain("todohaemil.com")
.path("/")
.secure(true)
.httpOnly(true)
Expand All @@ -218,20 +197,19 @@ public ResponseCookie saveHttpCookie(AuthTokens token) {
return httpCookie;
}

private Long findOrCreateUser(OAuthInfoResponse oAuthInfoResponse, Boolean isGuardian) {
private Long findOrCreateUser(OAuthInfoResponse oAuthInfoResponse) {
return userRepository.findByEmail(oAuthInfoResponse.getEmail())
.map(User::getId)
.orElseGet(() -> newUser(oAuthInfoResponse, isGuardian));
.orElseGet(() -> newUser(oAuthInfoResponse));
}

private Long newUser(OAuthInfoResponse oAuthInfoResponse, Boolean isGuardian) {
private Long newUser(OAuthInfoResponse oAuthInfoResponse) {
User user = User.builder()
.email(oAuthInfoResponse.getEmail())
.nickname(oAuthInfoResponse.getNickname())
.profileImageUrl(oAuthInfoResponse.getProfileImageUrl())
.oAuthProvider(oAuthInfoResponse.getOAuthProvider())
.role(User.Role.USER) // 추가.
.guardian(isGuardian)
.build();

return userRepository.save(user).getId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ public AuthTokens generate(String provider, Long userId, String email) {

// Redis에 RT 저장
saveRefreshToken(provider, email, refreshToken);
log.info("Redis 저장 완료");

return AuthTokens.of(accessToken, refreshToken, BEARER_TYPE, ATPeriod / 1000L);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.haemil.backend.global.security.oauth;

public enum OAuthProvider {
KAKAO, GOOGLE
KAKAO, NAVER
}
Loading
Loading