이번 포스팅에서는 마지막으로 회원 가입을 통해 데이터베이스에 회원 정보를 저장하고, 로그인을 통해 JWT를 생성하여, 권한에 따른 리소스에 접근 시 발급받은 JWT를 통해 검증하고 접근하는 로직을 개발해보자.
먼저 회원가입 로직을 개발하기 위해서 MemberService를 구현하자.
MemberService
[ SecurityUtil ]
먼저, MemberService를 구현하기 앞서, 현재 유저의 이름을 반환하는 메서드를 가지고 있는 클래스를 생성하자.
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.info("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);
}
}
[ MemberService ]
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {
private final MemberRepository memberRepository;
private final PasswordEncoder passwordEncoder;;
// 회원가입 로직으로, 일반 회원이므로 ROLE_USER 권한
@Transactional
public Member signup(MemberDto memberDto){
if(memberRepository.findOneWithAuthoritiesByUsername(memberDto.getUsername()).orElse(null) != null){
throw new RuntimeException("이미 가입되어 있는 회원입니다.");
}
Authority authority = Authority.builder()
.authorityName("ROLE_USER")
.build();
Member member = Member.builder()
.username(memberDto.getUsername())
.password(passwordEncoder.encode(memberDto.getPassword()))
.nickname(memberDto.getNickname())
.authorities(Collections.singleton(authority))
.activated(true)
.build();
return memberRepository.save(member);
}
// 유저이름으로 유저 객체와 권한정보 가져옴
public Optional<Member> getUserWithAuthorities(String username){
return memberRepository.findOneWithAuthoritiesByUsername(username);
}
// SecurityContext에 저장된 username의 정보만 가져옴
public Optional<Member> getMyUserWithAuthorities(){
return SecurityUtil.getCurrentUsername().flatMap(memberRepository::findOneWithAuthoritiesByUsername);
}
}
- signup() 메서드를 통해 회원가입을 진행 (일반 유저 이므로 ROLE_USER로 설정)
- getUserWithAuthorities()를 통해 유저 이름으로 유저 객체와 권한정보를 가져옴
- getMyUserWithAuthorities() 를 통해 SecurityContext에 저장된 username의 정보만 가져옴
마지막으로 회원가입을 요청할 컨트롤러 계층을 개발해보자.
MemberController
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class MemberController {
private final MemberService memberService;
@PostMapping("/signup")
public ResponseEntity<Member> signup(@Valid @RequestBody MemberDto memberDto){
return ResponseEntity.ok(memberService.signup(memberDto));
}
@GetMapping("/user")
@PreAuthorize("hasAnyRole('USER', 'ADMIN')")
public ResponseEntity<Member> getMyMemberInfo(){
return ResponseEntity.ok(memberService.getMyUserWithAuthorities().get());
}
@GetMapping("/user/{username}")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<Member> getMemberInfo(@PathVariable String username){
return ResponseEntity.ok(memberService.getUserWithAuthorities(username).get());
}
}
- "/api/signup"
- memberService를 통해 RequestBody를 통해 MemberDto 정보로 회원가입을 진행
- 성공하면 ResponseEntity에 담아 리턴
- "/api/user"
- @PreAuthorize : USER, ADMIN으로 두 개의 권한 중 하나라도 가지면 접근이 가능
- 현재 member의 정보를 조회하는 API
- "/api/user/{username}"
- @PathVariable : username
- @PreAuthorize : ADMIN
- 회원 정보를 username을 통해 검색하는 API
< 참고 자료 >
[무료] Spring Boot JWT Tutorial - 인프런 | 강의
Spring Boot, Spring Security, JWT를 이용한 튜토리얼을 통해 인증과 인가에 대한 기초 지식을 쉽고 빠르게 학습할 수 있습니다., - 강의 소개 | 인프런
www.inflearn.com