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

[#152] Refactor: SecurityConfig 권한 판별 메소드로 이동 #156

Merged
merged 1 commit into from
Jun 13, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.authorizeHttpRequests(authorizeRequests -> {
authorizeRequests
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.requestMatchers(HttpMethod.POST, "/signup").hasAuthority("ROLE_GUEST") // '/signup' api는 ROLE_GUEST 권한 로그인 사용자만 사용 가능. 이는 DB 속성값 & 헤더의 jwt 토큰에 등록해둔 권한도 바꾸어 재발급 받아야 한다.

.requestMatchers("/", "/error", "/favicon.ico", "/v3/api-docs/**", "/swagger-ui/**", "/swagger/**", "/health").permitAll()
.requestMatchers("/ws/**", "/oauth2/**", "/reissue").permitAll()
.requestMatchers("/ws/**", "/oauth2/**", "/reissue").permitAll();
// .requestMatchers("/**").permitAll() // Test 용도

.anyRequest().hasAnyAuthority("ROLE_USER", "ROLE_ADMIN"); // permit 지정한 경로들 외에는 전부 USER나 ADMIN 권한이 있어야지 url을 이용 가능하다. (GUEST 불가능)
})

.exceptionHandling(exceptionHandling -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@
import com.sajang.devracebackend.service.AuthService;
import com.sajang.devracebackend.service.AwsS3Service;
import com.sajang.devracebackend.service.UserService;
import com.sajang.devracebackend.util.SecurityUtil;
import io.jsonwebtoken.JwtException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;

@Service
Expand All @@ -44,9 +43,16 @@ public AuthDto.SignupResponse signup(MultipartFile imageFile, AuthDto.SignupRequ
// - 사진 변경O : if 'imageFile != null && signupRequestDto.getIsImageChange() == 1' --> AWS S3 업로드O
// - 기본사진으로 변경O : if 'imageFile == null && signupRequestDto.getIsImageChange() == 1' --> AWS S3 업로드X & User imageUrl값 null로 업데이트

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println("==========================\n" + LocalDateTime.now() + "\n" + authentication.getAuthorities() + "\n==========================");
User user = userService.findLoginUser();

// 회원가입 권한 예외처리 (signup은 Role이 GUEST인 사용자만 이용가능한 API임.)
boolean isHasGuestRole = SecurityUtil.isHasRole(Role.ROLE_GUEST.name());
if(isHasGuestRole == false || !user.getRole().equals(Role.ROLE_GUEST) || user.getBojId() != null) {
// reissue로 인한 재발급 이후에도 이전 엑세스 토큰으로 '/signup' 경로에 다시 접근할 경우, 토큰 내의 권한은 GUEST가 맞겠지만 DB 내의 권한은 USER이기에 이러한 비정상적인 접근을 방지할 수 있기 때문임.
throw new Exception400.UserBadRequest("이미 가입완료 되어있는 사용자입니다.");
}

// 백준id 예외처리
if(signupRequestDto.getBojId() == null) {
throw new Exception400.UserBadRequest("회원가입 bojId==null 에러");
}
Expand All @@ -55,15 +61,6 @@ public AuthDto.SignupResponse signup(MultipartFile imageFile, AuthDto.SignupRequ
}
UserServiceImpl.getSolvedCount(signupRequestDto.getBojId()); // solvedac 서버에 존재하지않는 백준id일경우 예외 처리.

User user = userService.findLoginUser();

// signup은 Role이 GUEST인 사용자만 이용가능한 API임.
if(!user.getRole().equals(Role.ROLE_GUEST) || user.getBojId() != null) {
// 이 로직을 SecurityConfig의 hasAuthority("ROLE_GUEST") 외에도 여기 또 써줘야하는 이유는,
// reissue로 인한 재발급 이후에도 이전 엑세스 토큰으로 '/signup' 경로에 다시 접근할 경우, 토큰 내의 권한은 GUEST가 맞겠지만 DB 내의 권한은 USER이기에 이러한 비정상적인 접근을 방지할 수 있기 때문임.
throw new Exception400.UserBadRequest("이미 가입완료 되어있는 사용자입니다.");
}

// 새 프로필 사진을 AWS S3에 업로드 후, 이미지 url 반환.
if(imageFile != null && signupRequestDto.getIsImageChange() == 1) { // 사진 변경O 경우
String uploadImageUrl = awsS3Service.uploadImage(imageFile);
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/com/sajang/devracebackend/util/SecurityUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

@Slf4j
Expand All @@ -15,7 +16,15 @@ public static Long getCurrentMemberId() { // 현재 로그인중인 사용자
if (authentication == null || authentication.getName() == null || authentication.getName().equals("anonymousUser")) {
throw new RuntimeException("Security Context에 인증 정보가 없습니다."); // @ExceptionHandler(Exception.class)에서 조건문으로 잡히도록 구성해두었음.
}

return Long.parseLong(authentication.getName());
}

public static boolean isHasRole(String roleName) {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication == null) {
throw new RuntimeException("Security Context에 인증 정보가 없습니다.");
}
return authentication.getAuthorities().contains(new SimpleGrantedAuthority(roleName));
}
}
Loading