Jwt_Security (4) - Jwt를 이용한 회원가입,로그인 구현

Yu Seong Kim·2024년 1월 10일
0

SpringBoot

목록 보기
9/29
post-thumbnail

Jwt와 Security 설정을 끝마쳤다. 전에 배운 내용이지만, 하나하나 구현하다 보니 어렵거나 헷갈리는 부분이 많았다.
이제 Jwt와 Security에 관한 내용들을 구현하고, 설정 하였으니 jwt를 이용한 회원가입과 로그인 기능을 RestApi로 구현해 볼 것입니다.

회원가입,로그인 로직

[회원가입과 로그인의 도메인은 sign-api로 통일 시켰습니다.]

회원가입 로직은 다음과 같습니다.

  1. 사용자 정보 입력 후 저장 -> admin,user 구분 (if 문으로 구분할 예정입니다.)
  2. 사용자 정보가 user 엔티티(DB)에 잘 들어왔는지 확인.
  3. 2번에서 확인은 결과에 대한 성공,실패 메서드를 따로 만들어서 호출 할 예정입니다.

로그인 로직은 다음과 같습니다.

  1. 사용자 정보중 Email을 불러옵니다.
  2. 사용자가 입력한 비밀번호와 데이터베이스에 저장된 비밀번호를 비교합니다.(일치 하지 않으면 RuntimeException())
  3. 만약 일치한다면 jwtProvider email과 role 값을 전달해서 토큰을 만들어 response에 넣어반환한다.

SignService(Interface)


public interface SignService {
    SignUpResultDto SignUp(SIgnUpDto sIgnUpDto,String roles);
    SignInResultDto SignIn(String email, String password);
}

SignServiceImpl


@Service
public class SignServiceImpl implements SignService {
    private Logger logger = LoggerFactory.getLogger(SignServiceImpl.class);

    private JwtProvider jwtProvider;
    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;
    @Autowired
    public SignServiceImpl(UserRepository userRepository , JwtProvider jwtProvider,
                           PasswordEncoder passwordEncoder){
        this.userRepository = userRepository;
        this.jwtProvider = jwtProvider;
        this.passwordEncoder = passwordEncoder;

    }

    @Override
    public SignUpResultDto SignUp(SIgnUpDto signUpDto, String roles){
        User user;
        if(roles.equalsIgnoreCase("admin")){
            user = User.builder()
                    .email(signUpDto.getEmail())
                    .password(passwordEncoder.encode(signUpDto.getPassword()))
                    .name(signUpDto.getName())
                    .roles(Collections.singletonList("ROLE_ADMIN"))
                    .build();
        }else{
            user = User.builder()
                    .email(signUpDto.getEmail())
                    .password(passwordEncoder.encode(signUpDto.getPassword()))
                    .name(signUpDto.getName())
                    .roles(Collections.singletonList("ROLE_USER"))
                    .build();
        }
        User saveduser = userRepository.save(user);

        SignUpResultDto signUpResultDto = new SignUpResultDto();
        logger.info("[getSignResultDto] User 정보 들어왔는지 확인 후 결과값 주입");

        if(!saveduser.getEmail().isEmpty()){
            setSucces(signUpResultDto);
        }else{
            setFail(signUpResultDto);
        }

        return signUpResultDto;


    }

    @Override
    public SignInResultDto SignIn(String email,String password)throws RuntimeException{
        User user = userRepository.getByEmail(email);
        if(!passwordEncoder.matches(password, user.getPassword())){
            throw new RuntimeException();
        }
        logger.info("[getSignInResult] 패스워드 일치");

        logger.info("[getSignInResult] SignInResultDto 객체 생성");
        SignInResultDto signInResultDto = SignInResultDto.builder()
                .token(jwtProvider.createToken(String.valueOf(user.getEmail()),
                        user.getRoles()))
                .build();
        logger.info("[getSignInResult] SignInResultDto 객체에 값 주입");
        setSucces(signInResultDto);
        return signInResultDto;
    }



    private void setSucces(SignUpResultDto result){
        result.setSuccess(true);
        result.setCode(CommonResponse.SUCCESS.getCode());
        result.setMsg(CommonResponse.SUCCESS.getMsg());
    }

    private void setFail(SignUpResultDto result){
        result.setSuccess(true);
        result.setCode(CommonResponse.Fail.getCode());
        result.setMsg(CommonResponse.Fail.getMsg());
    }



}

DTO값을 전달받아 값을 설정하는 CommonResponse클래스 생성, 회원가입, 로그인 값 전달 Dto 생성

SignUpResultDto

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class SignUpResultDto {
    private boolean success;

    private int code;

    private String msg;
}


SignUpDto

@Data
@Getter
@Setter
public class SIgnUpDto {
    private String email;
    private String password;
    private String name;
}

SignInResultDto

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class SignInResultDto extends SignUpResultDto{

  private String token;

    @Builder
    public SignInResultDto(boolean success, int code, String msg, String token) {
        super(success, code, msg);
        this.token = token;
    }
}

SignController

@RestController
@RequestMapping("/sign-api")
public class SignController {

    private Logger logger = LoggerFactory.getLogger(SignController.class);

    private SignService signService;

    @Autowired
    public SignController(SignService signService){
        this.signService = signService;
    }

    @PostMapping("/sign-up")
    public SignUpResultDto SignUp(@RequestBody SIgnUpDto signUpDto, String roles){
        logger.info("[signUp] 회원가입을 수행합니다. id : {}, password : ****, name : {}, role : {}", signUpDto.getEmail(),
                signUpDto.getPassword(),roles);
        SignUpResultDto signUpResultDto = signService.SignUp(signUpDto,roles);

        return signUpResultDto;
    }

    @PostMapping("/sign-in")
    public SignInResultDto SignIn(@RequestParam String email, String password) {
        logger.info("[sign-in] 로그인을 시도하고 있습니다. id : {}, password : *****", email);
        SignInResultDto signInResultDto = signService.SignIn(email, password);
        if(signInResultDto.getCode() == 0){
            logger.info("[sign-in] 정상적으로 로그인이 되었습니다. id: {}, token : {}",email,signInResultDto.getToken());
            signInResultDto.getToken();
        }
        return signInResultDto;
        }
    @GetMapping(value = "/exception")
    public void exceptionTest()throws  RuntimeException{
        throw new RuntimeException("접근이 금지 되었습니다.");
     }

    @ExceptionHandler(value = RuntimeException.class)
    public ResponseEntity<Map<String, String>> ExceptionHandler(RuntimeException e) {
        HttpHeaders responseHeaders = new HttpHeaders();
        //responseHeaders.add(HttpHeaders.CONTENT_TYPE, "application/json");
        HttpStatus httpStatus = HttpStatus.BAD_REQUEST;

        logger.error("ExceptionHandler 호출, {}, {}", e.getCause(), e.getMessage());

        Map<String, String> map = new HashMap<>();
        map.put("error type", httpStatus.getReasonPhrase());
        map.put("code", "400");
        map.put("message", "에러 발생");

        return new ResponseEntity<>(map, responseHeaders, httpStatus);
        
    	}
    }

스웨거를 이용한 회원가입, 로그인 테스트

-동작 시나리오-
1.회원가입 성공
2.회원가입을 성공한 계정을 바탕으로 로그인 -> 성공하면 Jwt 토큰 발급.

이전 포스트에서 설정한 스웨거를 이용하여 테스트를 할 예정이다.
http://localhost:8080/swagger-ui.html#/ -> 스웨거 URL
스웨거 주소로 들어가면 controller가 api문서로 자동화 되어 볼수 있다.

<회원가입 진행>

<회원가입 성공 response>

회원가입 한 정보를 가지고 로그인 진행.
<아이디, 비밀번호 입력>

<로그인 결과>

jwt토큰 반환 성공!!!!!

다음 포스트는 간단한 CRUD 게시판 RESTAPI에 회원가입 로그인을 합쳐보겠습니다.

profile
인생을 코딩하는 남자.

0개의 댓글