인프런의 Spring Boot JWT Tutorial의 강의를 보고 정리해 보았습니다.
이전 파트에서 Repository, 로그인 API 구현에 대해서 기록하였다.
[Spring Boot JWT Tutorial - 인프런] 스프링 JWT 적용하기 part3. Repository, 로그인 API 구현
SecurityUtil
- Security관련 간단한 메서드들 구현
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;
public class SecurityUtil {
private static final Logger logger = LoggerFactory.getLogger(SecurityUtil.class);
private SecurityUtil() {}
//SecurityContext의 Authentication 객체를 이용해 username을 리턴해주는 간단한 유틸성 메서드
public static Optional<String> getCurrentUsername() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
logger.debug("Security Context에 인증 정보가 없습니다.");
return Optional.empty();
}
//SecurityContext에 Authentication 객체가 저장되는 시점은 JwtFilter의 doFilter메서드에서 Request가 들어올 때 SecurityContext에 Authentication 객체를 저장해서 사용하게 된다.
String username = null;
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
username = springSecurityUser.getUsername();
} else if (authentication.getPrincipal() instanceof String) {
username = (String) authentication.getPrincipal();
}
return Optional.ofNullable(username);
}
}
UserService
- 회원 가입
- 유저 조회
import java.util.Collections;
import com.example.tutorial.Util.SecurityUtil;
import com.example.tutorial.dto.UserDto;
import com.example.tutorial.entity.Authority;
import com.example.tutorial.entity.User;
import com.example.tutorial.exception.DuplicateMemberException;
import com.example.tutorial.exception.NotFoundMemberException;
import com.example.tutorial.repository.UserRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
// 회원가입 로직 수행
@Transactional
public UserDto signup(UserDto userDto) {
파라미터로 받은 UserDto의 유저 이름을 가져와서 확인
if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) {
throw new DuplicateMemberException("이미 가입되어 있는 유저입니다.");
}
//권한 정보는 ROLE_USER로 초기화
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 UserDto.from(userRepository.save(user));
}
//로그인한 사람과는 관계 없이 username을 기준으로 유저 정보와 권한정보를 가져옴 -> Admin 계정인 경우
@Transactional(readOnly = true)
public UserDto getUserWithAuthorities(String username) {
return UserDto.from(userRepository.findOneWithAuthoritiesByUsername(username).orElse(null));
}
//SecurityContext에 저장된 username의 user 정보와 권한 정보만 가져옴
@Transactional(readOnly = true)
public UserDto getMyUserWithAuthorities() {
return UserDto.from(
SecurityUtil.getCurrentUsername()
.flatMap(userRepository::findOneWithAuthoritiesByUsername)
.orElseThrow(() -> new NotFoundMemberException("Member not found"))
);
}
}
UserController
import com.example.tutorial.dto.UserDto;
import com.example.tutorial.service.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
@RestController
@RequestMapping("/api")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/hello")
public ResponseEntity<String> hello() {
return ResponseEntity.ok("hello");
}
@PostMapping("/test-redirect")
public void testRedirect(HttpServletResponse response) throws IOException {
response.sendRedirect("/api/user");
}
@PostMapping("/signup")
public ResponseEntity<UserDto> signup(
@Valid @RequestBody UserDto userDto
) {
return ResponseEntity.ok(userService.signup(userDto));
}
@GetMapping("/user")
@PreAuthorize("hasAnyRole('USER','ADMIN')") //USER와 ADMIN 두가지 권한 모두 허용, 이 설정을 하기위해 SecurityConfig에서 @EnableGlobalMethodSecurity를 적용하였다.
public ResponseEntity<UserDto> getMyUserInfo(HttpServletRequest request) {
return ResponseEntity.ok(userService.getMyUserWithAuthorities());
}
@GetMapping("/user/{username}")
@PreAuthorize("hasAnyRole('ADMIN')") // ADMIN 권한만 호출할 수 있음
public ResponseEntity<UserDto> getUserInfo(@PathVariable String username) {
return ResponseEntity.ok(userService.getUserWithAuthorities(username));
}
}
'Spring' 카테고리의 다른 글
스프링 FeignClient (0) | 2023.05.09 |
---|---|
[Spring Batch] Batch 이해하기 (0) | 2023.03.07 |
[Spring Boot JWT Tutorial - 인프런] 스프링 JWT 적용하기 part3. Repository, 로그인 API 구현 (0) | 2022.09.03 |
[Spring Boot JWT Tutorial - 인프런] 스프링 JWT 적용하기 part2. JWT 관련 설정하기 (0) | 2022.09.03 |
[Spring Boot JWT Tutorial - 인프런] 스프링 JWT 적용하기 part1. 초기 세팅 (0) | 2022.09.03 |