Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
60e7f92
컨트롤러 수정
jun3327 Jan 19, 2024
1715e94
test
jun3327 Jan 19, 2024
6a5341c
test
jun3327 Jan 19, 2024
c7c7f6d
cache 삭제
jun3327 Jan 19, 2024
4c300d1
test
jun3327 Jan 19, 2024
1f57303
test
jun3327 Jan 19, 2024
dc9ecf9
merge conflicts 해결
jun3327 Jan 19, 2024
d12dd46
provider 수동으로 작성
jun3327 Jan 19, 2024
69191df
친구 목록 불러오기
jun3327 Jan 23, 2024
12af793
회원탈퇴
jun3327 Jan 23, 2024
1364235
친구 목록 불러오기 서ë¹수정
jun3327 Jan 23, 2024
211c5ec
test
jun3327 Jan 23, 2024
67e6c09
solving merge conflict
jun3327 Jan 23, 2024
ea6f351
test
jun3327 Jan 23, 2024
40f2db3
fix jwt create logic
jun3327 Jan 23, 2024
517773c
securityConfig, FriendDto 수정
jun3327 Jan 23, 2024
9cb9714
친구목록 불러오기 수정
jun3327 Jan 23, 2024
cfa6b52
account nickname, profileImage
jun3327 Jan 23, 2024
ad43316
fix securityConfig, controller url
jun3327 Jan 24, 2024
fc58826
ufix UserInfoDto
jun3327 Jan 24, 2024
d8d3400
profileImg update controller
jun3327 Jan 24, 2024
df0c9f5
feat deleteFriend Controller
jun3327 Jan 24, 2024
a3d1249
feat deleteFriend Service,Repository
jun3327 Jan 24, 2024
71d7f1f
fix friendshipDataRepository
jun3327 Jan 24, 2024
19a6552
fix friendshipRepository
jun3327 Jan 24, 2024
6d81c47
fix findFriends 메소드 FriendshipService로 옮김
jun3327 Jan 24, 2024
6108fb6
fix 각종 부연설명 주석
jun3327 Jan 24, 2024
9c34bf3
fix UserDto fields
jun3327 Jan 24, 2024
6baee9c
fix í” 로그인 후 프로필 ì„설정 url 변경
jun3327 Jan 24, 2024
0d70646
feat search friend api
jun3327 Jan 24, 2024
de3295f
fix friendship ㅈ 조회 방식 수정
jun3327 Jan 24, 2024
c40aa6f
fix 친구 삭제 로직 변경
jun3327 Jan 24, 2024
d2af596
fix user entity
jun3327 Jan 24, 2024
b7d4eb7
feat jwt refreshtoken
jun3327 Feb 1, 2024
064abc7
feat send friend request
jun3327 Feb 1, 2024
aa4f7a9
feat add friend
jun3327 Feb 1, 2024
869ef62
fix delete friend
jun3327 Feb 1, 2024
1b270f2
fix oauth login controller
jun3327 Feb 2, 2024
3175601
fix remove println
jun3327 Feb 2, 2024
3fe7424
fix oauthproperties
jun3327 Feb 2, 2024
3f5d7a8
Merge branch 'main' into KimHwanJun
jun3327 Feb 2, 2024
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
8 changes: 4 additions & 4 deletions ping/src/main/java/com/b6122/ping/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.filter.CorsFilter;

@Configuration
Expand Down Expand Up @@ -45,11 +46,10 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.httpBasic((httpBasic) -> httpBasic.disable()) //Bearer 방식을 사용하기 위해 basic 인증 비활성화
.authorizeHttpRequests((authorize) ->
authorize
.requestMatchers("/user/**").hasAnyRole("ADMIN", "MANAGER", "USER")
.requestMatchers("/oauth/jwt/**").permitAll()
.requestMatchers("/admin/**").hasAnyRole("ADMIN")
.anyRequest().permitAll());


.requestMatchers("/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated());


return http.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.b6122.ping.auth.PrincipalDetails;
import com.b6122.ping.domain.User;
import com.b6122.ping.dto.UserDto;
import com.b6122.ping.repository.UserRepository;
import com.b6122.ping.repository.datajpa.UserDataRepository;
import com.b6122.ping.service.JwtService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -16,10 +21,13 @@
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import java.io.IOException;
import java.util.Map;

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

private UserRepository userRepository;
private UserDataRepository userDataRepository;
private JwtService jwtService;

public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
super(authenticationManager);
Expand All @@ -38,9 +46,40 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
}

//토큰 검증(동일한 토큰인지, 만료시간은 안지났는지 com.auth0.jwt 라이브러리가 확인해줌)
//access token과 refresh token을 검증
String username = null;
String token = request.getHeader(JwtProperties.HEADER_STRING).replace(JwtProperties.TOKEN_PREFIX, "");
String username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(token)
.getClaim("username").asString();
String tokenType = JWT.decode(token).getClaim("token_type").asString();

if (tokenType.equals("access")) {

try {
username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(token).getClaim("username").asString();

} catch(JWTVerificationException e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Access token is not valid. Please send refersh token.");
return;
}
} else if (tokenType.equals("refresh")) {

try {
username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(token).getClaim("username").asString();
User user = userDataRepository.findByUsername(username).orElseThrow(RuntimeException::new);
UserDto userDto = new UserDto(user.getId(), user.getUsername());
Map<String, String> jwtAccessToken = jwtService.createJwtAccessToken(userDto);

//refersh token이 유효하면 access token 새로 발급
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write("{\"access_token\": \"" + jwtAccessToken.get("access_token") + "\"}");
return;

} catch (JWTVerificationException e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Refresh token is not valid. Please login again.");
return;
}
}

if (username != null) {
User user = userRepository.findByUsername(username);
Expand Down
175 changes: 132 additions & 43 deletions ping/src/main/java/com/b6122/ping/controller/RestApiController.java
Original file line number Diff line number Diff line change
@@ -1,84 +1,173 @@
package com.b6122.ping.controller;

import com.b6122.ping.auth.PrincipalDetails;
import com.b6122.ping.domain.Friendship;
import com.b6122.ping.dto.UserDto;
import com.b6122.ping.service.JwtService;
import com.b6122.ping.service.KakaoOAuthService;
import com.b6122.ping.service.UserService;
import com.b6122.ping.service.GoogleOAuthService;
import com.b6122.ping.service.NaverOAuthService;
import com.b6122.ping.dto.UserProfileDto;
import com.b6122.ping.service.*;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;


@RestController
@RequiredArgsConstructor
public class RestApiController {

private final NaverOAuthService naverOAuthService;
private final GoogleOAuthService googleOAuthService;

private final JwtService jwtService;
private final UserService userService;
private final KakaoOAuthService oAuthService;
private final KakaoOAuthService kakaoOAuthService;
private final FriendshipService friendshipService;

//프론트엔드로부터 authorization code 받고 -> 그 code로 카카오에 accesstoken 요청
// 받아 온 access token으로 카카오 리소스 서버로부터 카카오 유저 정보 가져오기
// 가져온 정보를 기반으로 회원가입
// jwt accessToken을 리액트 서버에 return
@PostMapping("/oauth/jwt/{serverName}")
public ResponseEntity<Map<String, Object>> oauthLogin(@PathVariable("serverName") String server,
@RequestBody Map<String, Object> request) throws IOException {
if ("kakao".equals(server)) {
String accessToken = kakaoOAuthService.getKakaoAccessToken(request.get("code").toString());
Map<String, Object> userInfo = kakaoOAuthService.getKakaoUserInfo(accessToken);
UserDto userDto = userService.joinOAuthUser(userInfo);

return ResponseEntity.ok().body(jwtService.createJwtAccessAndRefreshToken(userDto));
} else if ("google".equals(server)) {
String accessToken = googleOAuthService.getGoogleAccessToken(request.get("code").toString());
Map<String, Object> userInfo = googleOAuthService.getGoogleUserInfo(accessToken);
UserDto userDto = userService.joinOAuthUser(userInfo);

return ResponseEntity.ok().body(jwtService.createJwtAccessAndRefreshToken(userDto));
} else {
Map<String, Object> data = new HashMap<>();
data.put("error", "Nothing matches to request");

return ResponseEntity.badRequest().body(data);
}
}


@PostMapping("/oauth/jwt/kakao")
public ResponseEntity<Map<String, String>> createJwt(@RequestBody Map<String, Object> request) throws IOException {
// 프론트엔드로부터 authorization code 받고 -> 그 code로 카카오에 accesstoken 요청
String accessToken = oAuthService.getKakaoAccessToken(request.get("code").toString());
/**
* @param file : 사용자가 업로드한 이미지 파일 (form data)
* @param nickname : 사용자가 설정한 고유 nickname
*/
@PostMapping("/profile")
public void setInitialProfile(@RequestParam("profileImg") MultipartFile file,
@RequestParam("nickname") String nickname,
Authentication authentication) {
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
Long userId = principalDetails.getUser().getId();
userService.updateProfile(file, nickname, userId);

// 받아 온 access token으로 카카오 리소스 서버로부터 카카오 유저 정보 가져오기
Map<String, Object> userInfo = oAuthService.getKakaoUserInfo(accessToken);
}

//회원 탈퇴
@DeleteMapping("/account")
public void deleteAccount(Authentication authentication) {
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
userService.deleteAccount(principalDetails.getUser().getId());
}

// 가져온 정보를 기반으로 회원가입
UserDto userDto = userService.joinOAuthUser(userInfo);
//사용자 정보(닉네임, 사진) 가져오기
@GetMapping("/account")
public ResponseEntity<Map<String, Object>> account(Authentication authentication) {
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
UserProfileDto userInfoDto = userService.getUserProfile(principalDetails.getUser().getId());
Map<String, Object> data = new HashMap<>();
data.put("userInfo", userInfoDto);

// jwt accessToken을 리액트 서버에 return
return ResponseEntity.ok().body(jwtService.createJwtAccessToken(userDto));
return ResponseEntity.ok().body(data);
}

@PostMapping("/oauth/jwt/google")
public ResponseEntity<Map<String, String>> createGoogleJwt(@RequestBody Map<String, Object> request) throws IOException {
// Frontend sends the authorization code to the server
String authorizationCode = request.get("code").toString();
//회원정보 변경(일단 사진만, 닉네임까지 확장 가능)
@PostMapping("/account")
public void updateProfileImage(@RequestParam("profileImg") MultipartFile file,
Authentication authentication) {
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
userService.updateProfile(file,
principalDetails.getUser().getNickname(),
principalDetails.getUser().getId());
}

// Exchange the authorization code for an access token from Google
String accessToken = googleOAuthService.getGoogleAccessToken(authorizationCode);
/**
* 친구삭제
*
* @param request {"nickname" : "xxx"}
*/
@DeleteMapping("/friends")
public void deleteFriend(@RequestBody Map<String, Object> request, Authentication authentication) {
String friendNickname = request.get("nickname").toString();
UserProfileDto findUserDto = userService.findUserByNickname(friendNickname);
Long friendId = findUserDto.getId();

// Use the access token to fetch user information from Google
Map<String, Object> userInfo = googleOAuthService.getGoogleUserInfo(accessToken);
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
Long userId = principalDetails.getUser().getId();

// Process the user information and perform user registration if needed
UserDto userDto = userService.joinOAuthUser(userInfo);
friendshipService.deleteFriend(friendId, userId);

// Return the JWT access token to the React server
return ResponseEntity.ok().body(jwtService.createJwtAccessToken(userDto));
}

@CrossOrigin
@PostMapping("/oauth/jwt/naver")
public ResponseEntity<Map<String, String>> createJwtNaver(@RequestBody Map<String, Object> request) throws IOException {
// Frontend sends the authorization code, use it to request Naver for an access token
String accessToken = naverOAuthService.getNaverAccessToken(request.get("code").toString());

// Use the obtained access token to fetch Naver user information from Naver resource server
Map<String, Object> userInfo = naverOAuthService.getNaverUserInfo(accessToken);

// Based on the retrieved information, perform user registration
UserDto userDto = userService.joinOAuthUser(userInfo);
/**
* 사용자의 nickname을 검색하여 찾기
*
* @param nickname 쿼리 파라미터로 전달
* @return 사용자 정보(UserProfileDto -> nickname, profileImg), 친구 여부
*/
@GetMapping("/friends/search")
public ResponseEntity<Map<String, Object>> searchUser(@RequestParam("nickname") String nickname,
Authentication authentication) {
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
Map<String, Object> data = new HashMap<>();
try {
UserProfileDto result = userService.findUserByNickname(nickname);
Optional<Friendship> friendship =
friendshipService.findFriendByIds(principalDetails.getUser().getId(), result.getId());
data.put("userInfo", result);
data.put("isFriendWithMe", friendship.isPresent());
return ResponseEntity.ok().body(data);
} catch (EntityNotFoundException e) {
data.put("error", e.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(data);
}
}

// Return the JWT access token to the React server
return ResponseEntity.ok().body(jwtService.createJwtAccessToken(userDto));
//친구 신청
@PostMapping("/friends/search")
public void sendFriendRequest(Authentication authentication,
@RequestParam("id") Long toUserId) {
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
Long fromUserId = principalDetails.getUser().getId();
//userId는 친구 신청 하는 유저, friendId는 친구 신청 받는 유저
friendshipService.sendRequest(fromUserId, toUserId);
}

//친구 요청 수락
@PostMapping("/friends/pendinglist")
public void addFriend(Authentication authentication, @RequestParam("nickname") String nickname) {
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
Long toUserId = principalDetails.getUser().getId();

UserProfileDto findUserDto = userService.findUserByNickname(nickname);
Long fromUserId = findUserDto.getId();

//toUserId -> 친구 요청을 받은 유저
//fromUserId -> 친구 요청을 보낸 유저
friendshipService.addFriend(toUserId, fromUserId);

}
}
22 changes: 17 additions & 5 deletions ping/src/main/java/com/b6122/ping/domain/Friendship.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Friendship {

Expand All @@ -25,12 +27,22 @@ public class Friendship {
@Enumerated(EnumType.STRING)
private FriendshipRequestStatus requestStatus; // PENDING, ACCEPTED, REJECTED

private boolean isFriend;
private boolean isFriend = false;

public void setIsFriend(boolean isFriend) {
this.isFriend = isFriend;
}

public void setRequestStatus(FriendshipRequestStatus requestStatus) {
this.requestStatus = requestStatus;
}
//친구 요청 시 메소드
//fromUser와 toUser사이 정방향/역방향 레코드 모두 추가
// public static Friendship createFriendship() {
//
// }
public static Friendship createFriendship(User fromUser, User toUser) {
Friendship friendship = new Friendship();
friendship.fromUser = fromUser;
friendship.toUser = toUser;
friendship.requestStatus = FriendshipRequestStatus.PENDING;
return friendship;
}
}

5 changes: 1 addition & 4 deletions ping/src/main/java/com/b6122/ping/domain/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;

import java.util.ArrayList;
import java.util.List;

Expand All @@ -25,6 +24,7 @@
@Table(name = "post")
@NoArgsConstructor
public class Post extends TimeEntity{

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "post_id")
Expand Down Expand Up @@ -53,16 +53,13 @@ public class Post extends TimeEntity{
@OneToMany(mappedBy = "post")
private List<Like> likes = new ArrayList<>();



//연관관계 매서드//
public void setUser(User user) {
user.addPost(this); //user의 posts list에 post(this) 추가
}

/*

//like 눌렀을때
public void pushLike(Long uid){
postRepository.createLike(this.pid,uid);
postRepository.updateLikeCount(this.getLikeCount()+1, this.pid);
Expand Down
Loading