스프링부트 로그인 만들기

전수향·2022년 9월 7일
0

저번에 올렸던 회원가입에 이어 이번엔 로그인을 구현하는 방법에 대해 소개하겠습니다!
저만의 방법이니 참고해주세요!

UserLoginForm 만들기

import lombok.Getter;
import lombok.Setter;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;

@Getter
@Setter
public class UserLoginForm {
    @Size(min = 3, max = 25)
    @NotEmpty(message = "사용자ID는 필수항목입니다.")
    private String name;

    @NotEmpty(message = "비밀번호는 필수항목입니다.")
    private String password;
}

위와 같이 웹 페이지에서 받을 데이터 형식에 따라 Form을 만들어 주시면 됩니다.

UserRepository에 findByName추가하기

전에 만들어놨던 UserRepository에 findByName 즉, 이름으로 User 찾기 기능을 추가합니다.

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByName(String name);
}

findByName은 말 그대로 이름을 통해 User를 찾겠다는 것이고, 이 기능은 JpaRepository에서 지원하는 키워드입니다. Optional로 받는 이유는 유저를 찾지 못한 경우 null값이 입력되기 때문입니다.

UserLoginService 만들기

이제 로그인을 할 때 사용할 서비스를 만들어 줄 것입니다.

@RequiredArgsConstructor
@Service
public class UserLoginService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public boolean login(String username, String password) throws UsernameNotFoundException{
        Optional<User> _user = this.userRepository.findByName(username);
        if(_user.isEmpty()){
            throw new UsernameNotFoundException("사용자를 찾을 수 없음");
        }
        User user = _user.get();
        if(passwordEncoder.matches(password, user.getPassword())){
            System.out.println("true");
            return true;
        }
        else{
            System.out.println("false");
            return false;
        }
    }
}

위와 같이 유저 이름과, 비밀번호를 받고 UserRepository에 있는 findByName을 이용해 유저를 찾습니다. 유저가 있다면 찾은 유저의 비밀번호와 데이터로 받은 비밀번호가 일치하는지 검사합니다. 저는 이때 PasswordEncoder에 있는 matches 매소드(boolen 반환)를 사용했습니다! matches(암호화 전 비밀번호, 암호화 된 비밀번호) 이런 식으로 사용해주시면 됩니다. 이 메소드를 사용한 이유는 암호화 된 비밀번호와 그냥 비밀번호를 바로 비교할 수 없기 때문입니다! 이제 일치하면 true를 아니면 false를 반환합니다!

UserController에 login기능 추가

이제 컨트롤러에서 직접 요청을 받아 처리해보겠습니다.

	@PostMapping("/login")
    @ResponseBody
    public Map<String, Object> login(@Valid UserLoginForm user, BindingResult bindingResult){
        Map<String, Object> map = new LinkedHashMap<>();
        if(bindingResult.hasErrors()) {
            map.put("result", "error");
            return map;
        }
        boolean check = userLoginService.login(user.getName(), user.getPassword());
        if(check) {
            String token = securityService.createToken(user.getName(), (604800000));
            map.put("result", token);
        }
        else {
            map.put("result", "error");
        }
        return map;
    }

포스트 형식으로 요청을 받고, 만들어 두었던 UserLoginForm으로 데이터를 받습니다. 그리고 loginservice에 login기능을 사용하여 유저가 있는지 없는지 검사하고, 있다면 유저 이름을 바탕으로 jwt토큰을 만들어 다시 return해주고, 없다면 error를 return해줍니다!

그럼 이제 jwt토큰을 어떻게 만드는지 알아보야겠죠?

jwt토큰 만들기

jwt토큰을 만들 클래스를 하나 만들어 줍니다. 저는 SecurityService로 하였습니다!

@Service
public class SecurityService {
    public String createToken(String subject, long expTime){
        if(expTime <= 0) {
            throw new RuntimeException("만료시이 0보다 커야함!");
        }

        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        byte[] secretKeyBytes = DatatypeConverter.parseBase64Binary(SECRET_KEY);
        Key signingKey =  new SecretKeySpec(secretKeyBytes, signatureAlgorithm.getJcaName());

        return Jwts.builder()
                .setSubject(subject)
                .signWith(signingKey, signatureAlgorithm)
                .setExpiration(new Date(System.currentTimeMillis() + expTime))
                .compact();
    }

    public String getSubject(String token){
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(DatatypeConverter.parseBase64Binary(SECRET_KEY))
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }
}

위 처럼 만들어 보았는데, 우선 무엇을 통해 만들지와 만료시간을 입력 받고, HS256 알고리즘과 SECRET_KEY를 활용하여 jwt토큰을 만든다는 코드입니다. 전부 설명하기에는 긴 내용이니 검색하시고 따라치시면서 이해하시길 바랍니다!
SECRET_KEY는 여러분이 사용할 누구도 알 수 없는 값을 사용해주시면 됩니다. application.properties에 변수를 만들어 사용할 수도 있고, 유저의 비밀번호 값을 사용할 수도 있겠네요! 단 너무 짧으면 에러가 날 수 있다는 점 유의해 주세요!

오늘은 이렇게 회원가입에 이어 로그인을 만들어 보았는데, 부족하지만

참고가 될 수 있으면 좋겠습니다. 감사합니다!

profile
꿈나무 개발자

0개의 댓글