코드 그라데이션
JWT 예제 구현 (7) 회원가입, 권한 검증 로직 본문
UserController
package inflearn.freejwt.controller;
import inflearn.freejwt.dto.UserDto;
import inflearn.freejwt.entity.User;
import inflearn.freejwt.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RequiredArgsConstructor
@RestController
@RequestMapping("/api")
public class UserController {
private final UserService userService;
/**
* 사용자 회원가입을 처리하는 엔드포인트.
*
* @param userdto 회원가입 요청에 필요한 사용자 정보를 담은 DTO 객체
* @return 회원가입이 성공하면 사용자 정보를 담은 ResponseEntity를 반환
*/
@PostMapping("/signup")
public ResponseEntity<User> siginup(@Valid @RequestBody UserDto userdto) {
return ResponseEntity.ok(userService.signup(userdto));
}
/**
* 현재 사용자의 정보를 조회하는 엔드포인트.
* 사용자 및 관리자 역할을 가진 사용자만 접근할 수 있다.
*
* @return 현재 사용자의 정보를 담은 ResponseEntity를 반환
*/
@GetMapping("/user")
@PreAuthorize("hasAnyRole('USER', 'ADMIN')")
public ResponseEntity<User> getMyUserInfo() {
// userService를 사용하여 현재 사용자의 정보를 조회하고, 그 결과를 ResponseEntity로 반환.
// getMyUserWithAuthorities()는 현재 사용자의 정보와 권한 정보를 함께 조회하는 서비스 메서드.
// 반환된 정보는 ResponseEntity.ok()를 사용하여 HTTP 200 OK 상태와 함께 반환됨.
return ResponseEntity.ok(userService.getMyUserWithAuthorities().get());
}
/**
* 특정 사용자의 정보를 조회하는 엔드포인트.
* 관리자 역할을 가진 사용자만 접근할 수 있다.
*
* @param username 조회할 사용자의 이름
* @return 특정 사용자의 정보를 담은 ResponseEntity를 반환
*/
@GetMapping("/user/{username}")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<User> getUserInfo(@PathVariable String username) {
// userService를 사용하여 특정 사용자의 정보를 조회하고, 그 결과를 ResponseEntity로 반환함.
// getUserWithAuthorities(username)는 특정 사용자 정보와 권한 정보를 함께 조회하는 서비스 메서드.
// 반환된 정보는 ResponseEntity.ok()를 사용하여 HTTP 200 OK 상태와 함께 반환됨.
return ResponseEntity.ok(userService.getUserWithAuthorities(username).get());
}
}
UserService
package inflearn.freejwt.service;
import inflearn.freejwt.dto.UserDto;
import inflearn.freejwt.entity.Authority;
import inflearn.freejwt.entity.User;
import inflearn.freejwt.repository.UserRepository;
import inflearn.freejwt.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.Optional;
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Transactional
public User signup(UserDto userDto) {
if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) {
throw new RuntimeException("이미 가입되어 있는 유저입니다.");
}
// 권한 정보 생성
Authority authority = Authority.builder()
.authorityName("ROLE_USER")
.build();
// 유저 정보 생성
User user = User.builder()
.username(userDto.getUsername())
.password(passwordEncoder.encode(userDto.getPassword()))
.nickname(userDto.getNickname())
.authorities(Collections.singleton(authority))
.activated(true)
.build();
// 저장
return userRepository.save(user);
}
/**
*
* @param username
* @return
* username을 기준으로 정보를 가져오는 메서드
*/
@Transactional(readOnly = true)
public Optional<User> getUserWithAuthorities(String username) {
return userRepository.findOneWithAuthoritiesByUsername(username);
}
/**
* SecurityContext에 저장된 username의 정보만 가져온다.
* @return
*/
@Transactional(readOnly = true)
public Optional<User> getMyUserWithAuthorities() {
return SecurityUtil.getCurrentUsername().flatMap(userRepository::findOneWithAuthoritiesByUsername);
}
}
util/SecurityUtil
package inflearn.freejwt.util;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Optional;
@NoArgsConstructor
public class SecurityUtil {
private static final Logger logger = LoggerFactory.getLogger(SecurityUtil.class);
/**
* 이 메서드의 역할은 Security Context의 Authentication 객체를 이용해 username을 리턴해주는 간단한 유틸성 메서드
*
* @return 현재 사용자의 username을 Optional<String> 형태로 반환. 인증 정보가 없으면 Optional.empty() 반환.
*/
public static Optional<String> getCurrentUsername() {
// 현재의 Authentication 객체를 가져온다.
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 인증 정보가 없는 경우
if (authentication == null) {
logger.debug("Security Context에 인증 정보가 없습니다.");
return Optional.empty(); // 빈 Optional 반환
}
String username = null;
// Authentication 객체의 주체(principal)를 확인
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
username = springSecurityUser.getUsername(); // UserDetails에서 username을 가져옴
}
else if (authentication.getPrincipal() instanceof String) {
username = (String) authentication.getPrincipal(); // 문자열로 된 주체의 경우, username으로 설정
}
return Optional.ofNullable(username); // Optional로 username 반환 (null인 경우에도 처리)
}
}
728x90
'Spring > Security' 카테고리의 다른 글
JWT 예제 구현 (8) 예외처리 로직 추가, Exception(핸들러) 추가, 버전 2.53 업그레이드 등 (0) | 2023.12.16 |
---|---|
[중간점검] JWT 2.41 버전 구현 로직 완성 코드 (0) | 2023.12.15 |
JWT 예제 구현 (6) Dto, Repository, UserDetailsService 구현 인터페이스 (0) | 2023.12.12 |
JWT 예제 구현 (5) 5개의 클래스를 SecurityConfig에 적용 (0) | 2023.12.11 |
JWT 예제 구현 (4) JWT 기본 코드 구현 + Security 설정 추가 (1) | 2023.12.11 |
Comments