SpringBootProject/SringBoot_JWT_RestApi

Chaptor.05 - 회원가입 API 생성 , 권한검증 테스트

ironmask431 2022. 4. 3. 19:29

<진행 할 것>

- 회원가입 api 생성

- 권한검증 확인

 

1. util 패키지 생성 > SecurityUtil.java 클래스 생성

 

package com.leesh.springbootjwttutorial.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Slf4j
@Component
public class SecurityUtil {

    //현재 security context에 인증된 사용자 username 조회
    public static Optional<String> getCurrentUsername(){
        final Authentication authentication = SecurityContextHolder
                .getContext().getAuthentication();

        if(authentication == null){
            log.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);
    }
}

 

2. service 패키지 > UserService.java 생성

 

package com.leesh.springbootjwttutorial.service;

import com.leesh.springbootjwttutorial.dto.UserDto;
import com.leesh.springbootjwttutorial.entity.Authority;
import com.leesh.springbootjwttutorial.entity.User;
import com.leesh.springbootjwttutorial.repository.UserRepository;
import com.leesh.springbootjwttutorial.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;

@Slf4j
@RequiredArgsConstructor
@Service
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    //회원가입
    @Transactional
    public User signup(UserDto userDto){
        if(userRepository.findOneWithAuthoritiesByEmail(userDto.getEmail()).orElse(null) != null){
            throw new RuntimeException(("이미 가입되어 있는 유저입니다."));
        }

        //권한entity, 유저entity 생성
        Authority authority = Authority.builder()
                .authorityName("ROLE_USER")
                .build();

        User user = User.builder()
                .email(userDto.getEmail())
                .password(passwordEncoder.encode(userDto.getPassword())) //패스워드 암호화
                .authorities(Collections.singleton(authority))
                .activated(true)
                .build();

        return userRepository.save(user);
    }

    //email로 회원정보 조회
    @Transactional(readOnly = true)
    public Optional<User> getUserWithAuthorities(String email){
        return userRepository.findOneWithAuthoritiesByEmail(email);
    }

    //현재 인증된 사용자의 회원정보 조회
    @Transactional(readOnly = true)
    public Optional<User> getMyUserWithAuthorities(){
        log.info(SecurityUtil.getCurrentUsername().toString());
        return SecurityUtil.getCurrentUsername()
                .flatMap(email -> userRepository.findOneWithAuthoritiesByEmail(email));
    }
}

 

3. UserController.java 생성

 

package com.leesh.springbootjwttutorial.controller;

import com.leesh.springbootjwttutorial.entity.User;
import com.leesh.springbootjwttutorial.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

/**
 * 유저 API 컨트롤러
 */
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/user")
public class UserController {
    private final UserService userService;

    //현재인증된 사용자의 정보 조회 (나의 정보조회)
    //USER, ADMIN 권한 접근 가능
    @GetMapping("/myInfo")
    @PreAuthorize("hasAnyRole('USER','ADMIN')")
    public ResponseEntity<User> getMyUserInfo(){
        return ResponseEntity.ok(userService.getMyUserWithAuthorities().get());
    }

    //EMAIL로 회원정보 조회
    //ADMIN 권한 접근 가능
    @GetMapping("/email/{email}")
    @PreAuthorize("hasAnyRole('ADMIN')")
    public ResponseEntity<User> getUserInfo(@PathVariable String email){
        return ResponseEntity.ok(userService.getUserWithAuthorities(email).get());
    }
}

 

4. JoinController.java 생성

 

package com.leesh.springbootjwttutorial.controller;

import com.leesh.springbootjwttutorial.dto.UserDto;
import com.leesh.springbootjwttutorial.entity.User;
import com.leesh.springbootjwttutorial.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

/**
 * 회원가입 API 컨트롤러
 */
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/join")
public class JoinController {
    private final UserService userService;

    //회원가입 - email, password 입력
    @PostMapping("/signup")
    public ResponseEntity<User> signup(@Valid @RequestBody UserDto userDto){
        return ResponseEntity.ok(userService.signup(userDto));
    }
}

 

5. 서버구동, /signup 회원가입 테스트, /login 로그인 테스트

 

회원가입 정상 확인

 

가입한 회원 id/pw로 로그인(토큰발급)도 정상 확인

h2 console 에서도 user 테이블에 정상 입력 된 것 확인함.

 

6. 권한 테스트 - User 권한을 가진 leesh@gmail.com 계정 토큰 으로 /myInfo 조회 

> 정상 확인

 

 

7. User 권한을 가진 leesh@gmail.com 계정 토큰 으로 /api/user/email/{email} 조회

> 403 접근 거부 에러 확인

 

 

8. ADMIN 권한을 가진 admin@gmail.com 계정 토큰으로 /api/user/email/{email} 조회

먼저 admin@gmail.com 계정으로 로그인하여 토큰을 다시 발급 받은 후 api 실행

> 정상 확인