Skip to content

Commit

Permalink
Merge pull request #26 from Team-UMC/feature/#22/member-api
Browse files Browse the repository at this point in the history
[FEAT] 일반 유저용 멤버 관련 API 구현
  • Loading branch information
kyxxgsoo authored Jan 22, 2024
2 parents 479b1bb + 0a5feec commit 89ca2bd
Show file tree
Hide file tree
Showing 67 changed files with 2,434 additions and 488 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ dependencies {
// swagger setting
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

// webClient setting
implementation 'org.springframework.boot:spring-boot-starter-webflux'

// s3 setting
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

Expand All @@ -58,6 +55,9 @@ dependencies {

// 스프링 시큐리티를 테스트하기 위한 의존성 추가
testImplementation 'org.springframework.security:spring-security-test'

// 다른 서버와 통신을 위한 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-webflux'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.umc.networkingService.config;

import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
import com.umc.networkingService.domain.member.repository.MemberRepository;
import com.umc.networkingService.global.common.exception.ErrorCode;
import com.umc.networkingService.global.common.exception.RestApiException;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,26 @@ public class JwtAuthenticationFilter extends GenericFilterBean {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// refresh Token이 있다면 refresh Token 사용
String refreshToken = jwtTokenProvider.resolveRefreshToken((HttpServletRequest) request);
String token = jwtTokenProvider.resolveToken((HttpServletRequest) request);
if (refreshToken != null && ((HttpServletRequest) request).getRequestURI()
.equals("/members/refresh") && jwtTokenProvider.validateRefreshToken(refreshToken)) {
Authentication authentication = jwtTokenProvider.getRefreshAuthentication(refreshToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
} else if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication authentication = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
String token = jwtTokenProvider.resolveRefreshToken((HttpServletRequest) request);

if(token != null) {
if (token.startsWith("Bearer ")) token = token.substring(7);

if (((HttpServletRequest) request).getRequestURI()
.equals("/members/token/refresh") && jwtTokenProvider.validateRefreshToken(token)) {
Authentication authentication = jwtTokenProvider.getRefreshAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} else {
token = jwtTokenProvider.resolveToken((HttpServletRequest) request);
if (token != null) {
if (token.startsWith("Bearer ")) token = token.substring(7);

if (jwtTokenProvider.validateToken(token)) {
Authentication authentication = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
chain.doFilter(request, response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,9 @@
import com.umc.networkingService.config.security.auth.PrincipalDetailsService;
import com.umc.networkingService.global.common.exception.ErrorCode;
import com.umc.networkingService.global.common.exception.RestApiException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.*;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
Expand All @@ -23,6 +16,7 @@

import java.util.Base64;
import java.util.Date;
import java.util.UUID;

@Component
@RequiredArgsConstructor
Expand All @@ -47,10 +41,13 @@ protected void init() {
refreshSecretKey = Base64.getEncoder().encodeToString(refreshSecretKey.getBytes());
}

public String generateAccessToken(Claims claims) {
public String generateAccessToken(UUID memberId) {
Date now = new Date();
Date accessTokenExpirationTime = new Date(now.getTime() + TOKEN_VALID_TIME);

Claims claims = Jwts.claims();
claims.put("memberId", memberId);

return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now) // 토큰 발행 시간 정보
Expand All @@ -59,10 +56,13 @@ public String generateAccessToken(Claims claims) {
.compact();
}

public String generateRefreshToken(Claims claims) {
public String generateRefreshToken(UUID memberId) {
Date now = new Date();
Date refreshTokenExpirationTime = new Date(now.getTime() + REF_TOKEN_VALID_TIME);

Claims claims = Jwts.claims();
claims.put("memberId", memberId);

return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now) // 토큰 발행 시간 정보
Expand All @@ -73,11 +73,8 @@ public String generateRefreshToken(Claims claims) {

public TokenInfo generateToken(UUID memberId) {

Claims claims = Jwts.claims();
claims.put("memberId", memberId);

String accessToken = generateAccessToken(claims);
String refreshToken = generateRefreshToken(claims);
String accessToken = generateAccessToken(memberId);
String refreshToken = generateRefreshToken(memberId);

return new TokenInfo(accessToken, refreshToken);
}
Expand Down Expand Up @@ -125,7 +122,7 @@ public boolean validateToken(String token) {
Jwts.parser().setSigningKey(jwtSecretKey).parseClaimsJws(token);
return true;
} catch (SecurityException | MalformedJwtException e) {
throw new RestApiException(ErrorCode.INVALID_JWT);
throw new RestApiException(ErrorCode.INVALID_ACCESS_TOKEN);
} catch (ExpiredJwtException e) {
throw new RestApiException(ErrorCode.EXPIRED_MEMBER_JWT);
} catch (UnsupportedJwtException | SignatureException e) {
Expand All @@ -139,7 +136,7 @@ public boolean validateRefreshToken(String token) {
Jwts.parser().setSigningKey(refreshSecretKey).parseClaimsJws(token);
return true;
} catch (SecurityException | MalformedJwtException e) {
throw new RestApiException(ErrorCode.INVALID_JWT);
throw new RestApiException(ErrorCode.INVALID_REFRESH_TOKEN);
} catch (ExpiredJwtException e) {
throw new RestApiException(ErrorCode.EXPIRED_MEMBER_JWT);
} catch (UnsupportedJwtException | SignatureException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package com.umc.networkingService.domain.friend.entity;

import com.umc.networkingService.domain.member.entity.Member;
import jakarta.persistence.*;
import com.umc.networkingService.global.common.base.BaseEntity;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.SQLRestriction;
import org.hibernate.annotations.UuidGenerator;

import java.util.UUID;

@Getter
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor(access= AccessLevel.PROTECTED)
@SQLRestriction("deleted_at is null")
public class Friend extends BaseEntity {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.umc.networkingService.domain.friend.repository;

import com.umc.networkingService.domain.friend.entity.Friend;
import com.umc.networkingService.domain.member.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.UUID;

public interface FriendRepository extends JpaRepository<Friend, UUID> {
boolean existsBySenderAndReceiver(Member sender, Member receiver);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.umc.networkingService.domain.friend.service;

import com.umc.networkingService.domain.member.entity.Member;

public interface FriendService {
boolean checkFriend(Member sender, Member receiver);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.umc.networkingService.domain.friend.service;

import com.umc.networkingService.domain.friend.repository.FriendRepository;
import com.umc.networkingService.domain.member.entity.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class FriendServiceImpl implements FriendService {

private final FriendRepository friendRepository;

@Override
public boolean checkFriend(Member sender, Member receiver) {
return friendRepository.existsBySenderAndReceiver(sender, receiver);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.umc.networkingService.domain.member.client;

import com.umc.networkingService.domain.member.dto.client.github.GithubAccessTokenResponse;
import com.umc.networkingService.domain.member.dto.client.github.GithubInfoResponse;
import com.umc.networkingService.global.common.exception.ErrorCode;
import com.umc.networkingService.global.common.exception.RestApiException;
import org.springframework.beans.factory.annotation.Value;
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.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class GithubMemberClient {

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

@Value("${github.client-secret}")
private String clientSecret;

@Value("${github.redirect-uri}")
private String redirectUri;

private final WebClient webClient;

public GithubMemberClient() {
this.webClient = generateWebClient();
}

private WebClient generateWebClient() {
return WebClient.builder()
.baseUrl("https://github.com/login/oauth/access_token")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.build();
}

public String getAccessToken(final String code) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("client_id", clientId);
formData.add("client_secret", clientSecret);
formData.add("code", code);
formData.add("redirect_uri", redirectUri);

GithubAccessTokenResponse response = webClient
.post()
.body(BodyInserters.fromFormData(formData))
.retrieve()
.bodyToMono(GithubAccessTokenResponse.class)
.blockOptional()
.orElseThrow(() -> new RestApiException(ErrorCode.FAILED_GITHUB_AUTHENTICATION));

if (response == null)
throw new RestApiException(ErrorCode.FAILED_GITHUB_AUTHENTICATION);

return response.getAccessToken();
}

public String getGithubNickname(final String code) {
String accessToken = getAccessToken(code);

WebClient userWebClient = WebClient.builder()
.baseUrl("https://api.github.com/user")
.build();

GithubInfoResponse response = userWebClient
.get()
.headers(headers -> headers.setBearerAuth(accessToken))
.retrieve()
.bodyToMono(GithubInfoResponse.class)
.block();

if (response == null)
throw new RestApiException(ErrorCode.FAILED_SOCIAL_LOGIN);

return response.getLogin();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public String getgoogleClientID(final String accessToken) {
.block();

if(response == null)
throw new RestApiException(ErrorCode._INTERNAL_SERVER_ERROR);
throw new RestApiException(ErrorCode.FAILED_SOCIAL_LOGIN);

return response.getSub();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public String getkakaoClientID(final String accessToken) {
.block();

if(response == null)
throw new RestApiException(ErrorCode._INTERNAL_SERVER_ERROR);
throw new RestApiException(ErrorCode.FAILED_SOCIAL_LOGIN);

return response.getId();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public String getnaverClientID(final String accessToken){
.block();

if(response == null)
throw new RestApiException(ErrorCode._INTERNAL_SERVER_ERROR);
throw new RestApiException(ErrorCode.FAILED_SOCIAL_LOGIN);

return response.getResponse().getId();
}
Expand Down
Loading

0 comments on commit 89ca2bd

Please sign in to comment.