Skip to content

Commit

Permalink
Merge pull request #52 from Techeer-TeamC/feature/social-login-refactor
Browse files Browse the repository at this point in the history
Feature/social login refactor
  • Loading branch information
somii009 authored Jul 15, 2022
2 parents 344807d + 9f3b7e4 commit 51ebb98
Show file tree
Hide file tree
Showing 12 changed files with 396 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.Techeer.Team_C.domain.auth.controller;

import com.Techeer.Team_C.domain.auth.entity.AuthorizationKakao;
import com.Techeer.Team_C.domain.user.dto.LoginFormDto;
import com.Techeer.Team_C.domain.auth.dto.TokenDto;
import com.Techeer.Team_C.domain.auth.dto.TokenRefreshDto;
import com.Techeer.Team_C.domain.auth.service.AuthService;

import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.json.simple.JSONObject;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.core.OAuth2Token;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
Expand Down Expand Up @@ -55,15 +56,17 @@ public ResponseEntity<Void> logout(@RequestBody TokenRefreshDto tokenRefreshDto)
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

@GetMapping("/kakao")
@GetMapping("/token/kakao")
@ApiOperation(value = "kakao 소셜 로그인", notes = "소셜로그인 API (kakao)")
public void kakaoCallback(@RequestParam String code) {
System.out.println(code);
public ResponseEntity<TokenDto> kakaoCallback(@RequestParam("code") String code) {

return ResponseEntity.ok(authService.oauth2AuthorizationKakao(code));
}

@GetMapping("/google")
@GetMapping("/token/google")
@ApiOperation(value = "google 소셜 로그인", notes = "소설로그인 API (google)")
public void googleCallback(@RequestParam String code) {
System.out.println(code);
public ResponseEntity<TokenDto> googleCallback(@RequestParam("code") String code) {

return ResponseEntity.ok(authService.oauth2AuthorizationGoogle(code));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.Techeer.Team_C.domain.user.entity.User;
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.Techeer.Team_C.domain.auth.entity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class AuthorizationGoogle {
private String access_token;
private String expires_in;
private String id_token;
private String scope;
private String token_type;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.Techeer.Team_C.domain.auth.entity;

import lombok.Data;

@Data
public class AuthorizationKakao {
private String access_token;
private String token_type;
private String refresh_token;
private int expires_in;
private String scope;
private int refresh_token_expires_in;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@

package com.Techeer.Team_C.domain.auth.jwt;

import com.Techeer.Team_C.domain.auth.dto.TokenDto;
import com.Techeer.Team_C.domain.user.entity.Role;
import io.jsonwebtoken.*;

import javax.servlet.ServletRequest;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
Expand All @@ -30,14 +32,14 @@ public class JwtTokenProvider {
@Value("${jwt.secret}") //.yml파일을 통해 secret키 관리
private String secretKey;


private long tokenValidTime = 30 * 60 * 1000L; //토큰 유효시간 30분
private long refreshTokenValidTime = 7 * 24 * 60 * 60 * 1000L; // refresh 유효시간 : 7일

// 객체 초기화, secretKey를 Base64로 인코딩한다.
@PostConstruct
protected void init() {
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
secretKey = Base64.getEncoder()
.encodeToString(secretKey.getBytes());
}

// JWT 토큰 생성
Expand All @@ -50,7 +52,8 @@ protected void init() {
*/
public TokenDto createToken(Authentication authentication) {
// 권한들 가져오기
String authorities = authentication.getAuthorities().stream()
String authorities = authentication.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));

Expand Down Expand Up @@ -79,6 +82,33 @@ public TokenDto createToken(Authentication authentication) {
.build();
}

public TokenDto createTokenSocialLogin(Long userId) {

Role authority = Role.ROLE_USER;
long now = (new Date()).getTime();

// Access Token 생성
Date accessTokenExpiresIn = new Date(now + tokenValidTime);
String accessToken = Jwts.builder()
.setSubject(String.valueOf(userId)) // payload "sub": "name"
.claim(AUTHORITIES_KEY, authority) // payload "auth": "ROLE_USER"
.setExpiration(accessTokenExpiresIn) // payload "exp": 1516239022 (예시)
.signWith(SignatureAlgorithm.HS256, secretKey) // header "alg": "HS512"
.compact();

// Refresh Token 생성
String refreshToken = Jwts.builder()
.setExpiration(new Date(now + refreshTokenValidTime))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();

return TokenDto.builder()
.grantType(BEARER_TYPE)
.accessToken(accessToken)
.accessTokenExpiresIn(accessTokenExpiresIn.getTime())
.refreshToken(refreshToken)
.build();
}

public Authentication getAuthentication(String accessToken) {
// 토큰 복호화
Expand All @@ -89,10 +119,11 @@ public Authentication getAuthentication(String accessToken) {
}

// 클레임에서 권한 정보 가져오기
Collection<? extends GrantedAuthority> authorities =
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
Collection<? extends GrantedAuthority> authorities = Arrays.stream(claims.get(AUTHORITIES_KEY)
.toString()
.split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());

// UserDetails 객체를 만들어서 Authentication 리턴
UserDetails principal = new User(claims.getSubject(), "", authorities);
Expand All @@ -103,18 +134,24 @@ public Authentication getAuthentication(String accessToken) {
//토큰 복호화 함수
private Claims parseClaims(String accessToken) {
try {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(accessToken).getBody();
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(accessToken)
.getBody();
} catch (ExpiredJwtException e) {
return e.getClaims();
}
}


// 토큰의 유효성 + 만료일자 확인
public boolean validateToken(ServletRequest request, String jwtToken) {
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
return !claims.getBody().getExpiration().before(new Date());
Jws<Claims> claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwtToken);
return !claims.getBody()
.getExpiration()
.before(new Date());
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
log.info("잘못된 JWT 서명입니다.");
request.setAttribute("exception", INVALID_JTW_TOKEN_SIGNATURE);
Expand All @@ -140,8 +177,12 @@ public boolean validateToken(ServletRequest request, String jwtToken) {

public boolean validateToken(String jwtToken) {
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
return !claims.getBody().getExpiration().before(new Date());
Jws<Claims> claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwtToken);
return !claims.getBody()
.getExpiration()
.before(new Date());
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
log.info("잘못된 JWT 서명입니다.");
} catch (ExpiredJwtException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.Techeer.Team_C.domain.auth.service;

import com.Techeer.Team_C.domain.auth.entity.AuthorizationGoogle;
import com.Techeer.Team_C.domain.auth.entity.AuthorizationKakao;
import com.Techeer.Team_C.domain.auth.jwt.JwtTokenProvider;
import com.Techeer.Team_C.domain.auth.entity.RefreshToken;
import com.Techeer.Team_C.domain.auth.repository.RefreshTokenRepository;
import com.Techeer.Team_C.domain.auth.dto.TokenRefreshDto;
import com.Techeer.Team_C.domain.user.dto.LoginFormDto;
import com.Techeer.Team_C.domain.auth.dto.TokenDto;
import com.Techeer.Team_C.domain.user.dto.UserDto;
import com.Techeer.Team_C.domain.user.entity.User;
import com.Techeer.Team_C.domain.user.service.UserService;
import com.Techeer.Team_C.global.error.exception.BusinessException;
import io.jsonwebtoken.SignatureException;
Expand All @@ -28,6 +31,8 @@ public class AuthService {
private final RefreshTokenRepository refreshTokenRepository;
private final UserService userService;
private final PasswordEncoder passwordEncoder;
private final Oauth2Kakao oauth2Kakao;
private final Oauth2Google oauth2Google;

/**
* 로그인
Expand Down Expand Up @@ -56,8 +61,10 @@ public TokenDto login(LoginFormDto loginformDto) {
TokenDto tokenDto = tokenProvider.createToken(authentication);

// 4. RefreshToken 저장
RefreshToken refreshToken = RefreshToken.builder().key(authentication.getName())
.value(tokenDto.getRefreshToken()).build();
RefreshToken refreshToken = RefreshToken.builder()
.key(authentication.getName())
.value(tokenDto.getRefreshToken())
.build();

refreshTokenRepository.save(refreshToken);

Expand Down Expand Up @@ -119,18 +126,51 @@ public Authentication authenticationValidCheck(TokenRefreshDto tokenRefreshDto)
}

public RefreshToken refreshTokenValidCheck(Authentication authentication,
TokenRefreshDto tokenRefreshDto) {
TokenRefreshDto tokenRefreshDto) {
// 저장소에서 Member ID 를 기반으로 Refresh Token 값 가져옴
RefreshToken refreshToken = refreshTokenRepository.findByKey(authentication.getName())
.orElseThrow(
() -> new BusinessException("로그아웃된 사용자 입니다", LOGOUT_USER));

// Refresh Token 일치하는지 검사

if (!refreshToken.getValue().equals(tokenRefreshDto.getRefreshToken())) {
if (!refreshToken.getValue()
.equals(tokenRefreshDto.getRefreshToken())) {
throw new BusinessException("토큰과 유저정보가 서로 일치하지 않습니다.", MISMATCHED_USER_INFORMATION);
}
return refreshToken;
}

public TokenDto oauth2AuthorizationKakao(String code) {
AuthorizationKakao authorization = oauth2Kakao.getAccessTokenByCode(code);
User userInfoFromKakao = oauth2Kakao.getUserByAccessToken(authorization.getAccess_token());

// JWT 토큰 생성
TokenDto tokenDto = tokenProvider.createTokenSocialLogin(userInfoFromKakao.getUserId());

RefreshToken refreshToken = RefreshToken.builder()
.key(String.valueOf(userInfoFromKakao.getUserId()))
.value(tokenDto.getRefreshToken())
.build();
refreshTokenRepository.save(refreshToken);

return tokenDto;
}

public TokenDto oauth2AuthorizationGoogle(String code) {
AuthorizationGoogle authorization = oauth2Google.getAccessTokenByCode(code);
User userInfoFromGoogle = oauth2Google.getUserByAccessToken(authorization.getAccess_token());

TokenDto tokenDto = tokenProvider.createTokenSocialLogin(userInfoFromGoogle.getUserId());

RefreshToken refreshToken = RefreshToken.builder()
.key(String.valueOf(userInfoFromGoogle.getUserId()))
.value(tokenDto.getRefreshToken())
.build();
refreshTokenRepository.save(refreshToken);

return tokenDto;
}

}

Loading

0 comments on commit 51ebb98

Please sign in to comment.