-
JWT 실습 프로젝트 - 4 (회원가입, 권한검증)SPRING/스프링 시큐리티 -JWT 2021. 9. 18. 00:19
SecurityUtil
public class SecurityUtil { private static final Logger logger = LoggerFactory.getLogger(SecurityUtil.class); private SecurityUtil() { } public static Optional<String> getCurrentUsername() { final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null) { logger.debug("Security Context에 인증 정보가 없습니다."); return Optional.empty(); } 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); } }
getCurrentUsername() 메소드는 JwtFilter 클래스의 doFilter 메소드에서 저장한 Security Context의 인증 정보에서 username을 리턴함.
UserService
@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 User signup(UserDto userDto) { if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) { throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); } //빌더 패턴의 장점 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); } @Transactional(readOnly = true) public Optional<User> getUserWithAuthorities(String username) { return userRepository.findOneWithAuthoritiesByUsername(username); } @Transactional(readOnly = true) public Optional<User> getMyUserWithAuthorities() { return SecurityUtil.getCurrentUsername().flatMap(userRepository::findOneWithAuthoritiesByUsername); } }
signup()은 이미 같은 username으로 가입된 유저가 있는지 확인하고, UserDto 객체의 정보들을 기반으로 권한 객체와 유저 객체를 생성하여 DB에 저장함.
getMyUserWithAuthorities 메소드는 SecurityUtil의 getCurrentUsername() 메소드가 리턴하는 username의 유저 및 권한 정보를 리턴함.
UserController
@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("/signup") public ResponseEntity<User> signup( @Valid @RequestBody UserDto userDto ) { return ResponseEntity.ok(userService.signup(userDto)); } @GetMapping("/user") @PreAuthorize("hasAnyRole('USER','ADMIN')") public ResponseEntity<User> getMyUserInfo() { return ResponseEntity.ok(userService.getMyUserWithAuthorities().get()); } @GetMapping("/user/{username}") @PreAuthorize("hasAnyRole('ADMIN')") public ResponseEntity<User> getUserInfo(@PathVariable String username) { return ResponseEntity.ok(userService.getUserWithAuthorities(username).get()); } }
signup 메소드는 permitAll 이기 때문에 권한없이 호출이 가능하다.
getMyUserInfo 메소드는 현재 SecurityContxt에 저장되어 있는 인증 정보의 username을 기준으로 한 유저 정보 및 권한 정보를 리턴하는 API이다. @PreAuthorize를 통하여 ROLE_USER, ROLE_ADMIN 권한 모두 호출 가능하게 설정한다.
getUserInfo 메소드는 username을 파라미터로 받아 해당 username의 유저 정보 및 권한 정보를 리턴한다.
회원 가입 테스트
권한검증
아래와 같이 로그인
아래와 같이 Authorization Type을 지정하고, 포스트맨 전역 변수(jwt_tutorial_token)에 담았던 Token을 사용하여 권한 검증을 한다.
ADMIN 권한이 없는 경우에는 아래와 같이 FORBIDDEN 403 에러가 리턴되는 것을 확인 할 수 있다.
'SPRING > 스프링 시큐리티 -JWT' 카테고리의 다른 글
JWT 실습 프로젝트 - 3 (로그인) (0) 2021.09.17 JWT 실습 프로젝트 - 2 (Security 기본 설정, JWT 및 Security 설정) (0) 2021.09.17 JWT 실습 프로젝트 - 1 (프로젝트 생성 및 설정) (0) 2021.09.11 JWT란? (0) 2021.09.11