회원가입과 로그인 구현
스프링 시큐리티 설정 후에 회원가입과 로그인 구현하는 것에 대해 알아보겠습니다.
회원가입 구현
SignService 인터페이스 구현
public interface SignService {
/**
* 회원 가입
*/
SignUpResultDto signUp(String id, String password, String name, String role);
/**
* 로그인
*/
SignUpResultDto signIn(String id, String password) throws RuntimeException;
}
SignServiceImpl 클래스 (회원 가입)
@Override
public SignUpResultDto signUp(String id, String password, String name, String role) {
LOGGER.info("[getSignUpResult] 회원 가입 정보 전달");
User user;
if (role.equalsIgnoreCase("admin")) {
user = User.builder()
.uid(id)
.name(name)
.password(passwordEncoder.encode(password))
.roles(Collections.singletonList("ROLE_ADMIN"))
.build();
} else {
user = User.builder()
.uid(id)
.name(name)
.password(passwordEncoder.encode(password))
.roles(Collections.singletonList("ROLE_USER"))
.build();
}
User savedUser = userRepository.save(user);
SignInResultDto signInResultDto = new SignInResultDto();
LOGGER.info("[getSignUpResult] userEntity 값이 들어왔는지 확인 후 결과값 주입");
if (!savedUser.getName().isEmpty()) {
LOGGER.info("[getSignUpResult] 정상 처리 완료");
setSuccessResult(signInResultDto);
} else {
LOGGER.info("[getSignUpResult] 정상 처리 완료");
setFailResult(signInResultDto);
}
return signInResultDto;
}
- ADMIN과 USER로 권한을 구분한다.
- signUp( ) 메서드는 role 객체를 확인하여 User 엔티티에 roles 권한을 추가해서 엔티티를 생성한다.
- 패스워드는 암호화해야하기에 PasswordEncoder를 활용하여 인코딩을 수행한다.
- 생성된 엔티티를 UserRespository를 통해 저장한다.
SignServiceImpl 클래스 (로그인)
@Override
public SignUpResultDto signIn(String id, String password) throws RuntimeException {
LOGGER.info("[getSignInResult] signDataHandler 로 회원 정보 요청");
User user = userRepository.getByUid(id);
LOGGER.info("[getSignInResult] Id : {}", id);
LOGGER.info("[getSignInResult] 패스워드 비교 수행");
if (!passwordEncoder.matches(password, user.getPassword())) {
LOGGER.info("[getSignInResult] 패스워드 불일치");
throw new RuntimeException();
}
LOGGER.info("[getSignInResult] SignInResultDto 객체 생성");
SignInResultDto signInResultDto = SignInResultDto.builder()
.token(jwtTokenProvider.createToken(
String.valueOf(user.getUid()), user.getRoles()))
.build();
LOGGER.info("[getSignInResult] SignInResultDto 객체 주입");
setSuccessResult(signInResultDto);
return signInResultDto;
}
- 로그인은 미리 저장되어 있는 계정 정보와 요청을 통해 전달된 계정 정보가 일치하는지 확인하는 작업이다.
- 내부 로직 시퀀스
- id를 기반으로 UserRepository에서 User 엔티티를 가져온다.
- PasswordEncoder를 사용하여 데이터베이스에 저장되어 있던 패스워드와 입력받은 패스워드가 일치하는지 확인하는 작업을 수행한다.
- 패스워드가 일치해서 인증을 통과하면 JwtTokenProvider를 통해 id 와 role 값을 전달해서 토큰을 생성한 후 Response에 담아 전달한다.
SignServiceImpl 클래스 (성공 및 실패 결과)
- 회원가입과 로그인 메서드에서 사용할 수 있는 데이터를 설정하는 메서드이다.
- 각 메서드는 DTO를 전달받아 값을 설정한다.
private void setFailResult(SignInResultDto signInResultDto) {
signInResultDto.setSuccess(false);
signInResultDto.setCode(CommonResponse.FAIL.getCode());
signInResultDto.setMsg(CommonResponse.FAIL.getMsg());
}
private void setSuccessResult(SignInResultDto signInResultDto) {
signInResultDto.setSuccess(true);
signInResultDto.setCode(CommonResponse.SUCCESS.getCode());
signInResultDto.setMsg(CommonResponse.SUCCESS.getMsg());
}
CommonResponse 클래스 구현
@Getter
@AllArgsConstructor
public enum CommonResponse {
SUCCESS(0, "Success") ,
FAIL(-1, "Fail");
final int code;
final String msg;
}
PasswordEncoderConfiguration 클래스 구현
- PasswordEncoder는 별도의 @Configuration 클래스를 생성하고 @Bean 객체로 등록하도록 구현
@Configuration
public class PasswordEncoderConfiguration {
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
SignUpResultDto 클래스 구현
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class SignUpResultDto {
private boolean success;
private int code;
private String msg;
}
SignInResultDto 클래스 구현
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode(callSuper = true)
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")
@RequiredArgsConstructor
public class SignController {
private final Logger LOGGER = LoggerFactory.getLogger(SignController.class);
private final SignService signService;
@PostMapping(value = "/sign-in")
public SignInResultDto signIn(
@ApiParam(value = "ID", required = true) @RequestParam String id,
@ApiParam(value = "Password", required = true) @RequestParam String password
) throws RuntimeException {
LOGGER.info("[signIn] 로그인을 시도하고 있습니다. id : {}, pw : ****", id);
SignInResultDto signInResultDto = signService.signIn(id, password);
if (signInResultDto.getCode() == 0) {
LOGGER.info("[signIn] 정상적으로 로그인되었습니다. id : {}, token : {}" ,
id, signInResultDto.getToken());
}
return signInResultDto;
}
@PostMapping(value = "/sign-up")
public SignUpResultDto signUp(
@ApiParam(value = "ID", required = true) @RequestParam String id,
@ApiParam(value = "비밀번호", required = true) @RequestParam String password,
@ApiParam(value = "이름", required = true) @RequestParam String name,
@ApiParam(value = "권한", required = true) @RequestParam String role
) {
LOGGER.info("[signUp] 회원가입을 수행합니다. id : {}, 비밀번호 : ****," +
" name : {}, role : {}", id, name, role);
SignUpResultDto signUpResultDto = signService.signUp(id, password, name, role);
LOGGER.info("[signUp] 회원가입을 완료했습니다. id : {}", id);
return signUpResultDto;
}
@ExceptionHandler(value = RuntimeException.class)
public ResponseEntity<Map<String, String>> ExceptionHandler(RuntimeException e) {
HttpHeaders responseHeaders = new HttpHeaders();
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);
}
}
- 클라이언트는 계정을 생성하고 로그인 과정을 거쳐 토큰값을 전달받음으로써 애플리케이션에서 제공하는 API 서비스를 사용할 준비를 한다.
반응형
'Book > 스프링부트 핵심가이드' 카테고리의 다른 글
스프링 시큐리티(Spring Security) 구현(of. SecurityConfiguration) (1) | 2023.12.06 |
---|---|
스프링 시큐리티(Spring Security) 구현(of. Jwt Token) (1) | 2023.12.06 |
스프링 시큐리티(Spring Security)와 JWT (2) | 2023.12.05 |
댓글