회원가입 및 로그인을 처리할 서비스단과 컨트롤러를 만들어준다.
public interface SignService {
SignUpResultDto signUp(String id, String password, String name, String role);
// 회원가입
SignInResultDto signIn(String id, String password) throws RuntimeException;
// 로그인
}
@Service
public class SignServiceImpl implements SignService {
private final Logger LOGGER = LoggerFactory.getLogger(SignServiceImpl.class);
public UserRepository userRepository;
public JwtTokenProvider jwtTokenProvider;
public PasswordEncoder passwordEncoder;
@Autowired
public SignServiceImpl(UserRepository userRepository, JwtTokenProvider jwtTokenProvider, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.jwtTokenProvider = jwtTokenProvider;
this.passwordEncoder = passwordEncoder;
}
@Override
public SignUpResultDto signUp(String id, String password, String name, String role) {
LOGGER.info("[getSignUpResult] 회원 가입 정보 전달");
User user;
if(role.equalsIgnoreCase("admin")){ // role이 admin일 경우 ROLE_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);
SignUpResultDto signUpResultDto = new SignUpResultDto();
LOGGER.info("[getSignUpResult] userEntity 값이 들어왔는지 확인 후 결과값 주입");
if(!savedUser.getName().isEmpty()){
LOGGER.info("[getSignUpResult] 정상 처리 완료");
setSuccessResult(signUpResultDto);
}else{
LOGGER.info("[getSignUpResult] 실패 처리 완료");
setFailResult(signUpResultDto);
}
return signUpResultDto;
}
권한(String role)에 따라 User의 권한을 다르게 저장한다.
password
는 암호화를 위해 passwordEncoder
를 통해 인코딩 한 후 저장한다.
User
엔티티의 roles
는 List
기 때문에 Collections.singletoneList()
를 사용해 권한을 넣어준다.
결과값을 List형태로 바꿀 때 사용한다.
Arrays.asList 역시 배열을 리스트로 변환하는 데 원소가 하나일 때는 Collections.singletoneList()를 사용한다.
PasswordEncoder를 사용하기 위한 설정을 해준다.
@Configuration
public class PasswordEncoderConfiguration {
@Bean
public PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
private void setSuccessResult(SignUpResultDto result){
result.setSuccess(true);
result.setCode(CommonResponse.SUCESSS.getCode());
result.setMsg(CommonResponse.SUCESSS.getMsg());
}
private void setFailResult(SignUpResultDto result){
result.setSuccess(false);
result.setCode(CommonResponse.FAIL.getCode());
result.setMsg(CommonResponse.FAIL.getMsg());
}
}
public enum CommonResponse {
SUCESSS(0,"Success"),FAIL(-1,"Fail");
int code;
String msg;
CommonResponse(int code, String msg){
this.code = code;
this.msg = msg;
}
public int getCode(){
return code;
}
public String getMsg(){
return msg;
}
}
@Override
public SignInResultDto 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())){
throw new RuntimeException();
}
LOGGER.info("[getSignInResult] 패스워드 일치");
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;
}
User
의 id로 user 정보를 불러온 후 전달된 패스워드와 비교를 수행한다.
불일치할 시 RuntimeException을 발생 시키며 signInResultDto에 토큰을 생성한다.
성공 여부를 알려주는 success와 http 상태코드 메시지를 저장하는 회원가입 dto
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class SignUpResultDto {
private boolean success;
private int code;
private String msg;
}
로그인 성공 후 토큰값을 담을 dto
@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;
}
}
@RestController
@RequestMapping("/sign-api")
public class SignController {
private final Logger LOGGER = LoggerFactory.getLogger(SignController.class);
private final SignService signService;
@Autowired
public SignController(SignService signService){
this.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 : {}, password:****,name:{},role:{}",id,name,role);
SignUpResultDto signUpResultDto = signService.signUp(id,password,name,role);
return signUpResultDto;
}
@GetMapping(value = "/exception")
public void exceptionTest() throws RuntimeException{
throw new RuntimeException("접근이 금지되었습니다.");
}
@ExceptionHandler(value = RuntimeException.class)
public ResponseEntity<Map<String,String>> ExceptionHandler(RuntimeException e){
HttpHeaders responseHeader = 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,responseHeader,httpStatus);
}
}
각각 로그인, 회원가입, 오류가 발생해 리디렉션될 exception, RuntimeException 발생 시 이를 처리해주는 핸들러로 구성되어있다.