[ SpringSecurity + JWT + Redis ] 회원가입 구현

Dev_ch·2022년 11월 4일
0
본 글은 2022.10.20에 작성되었습니다.

개발하던 프로젝트에서 사용자의 계정의 권한과 인증에 대해서 처리를 할 때 항상 SpringSecurity와 JWT만을 이용했었는데 그러다 보니 로그아웃을 한다거나 AccessToken을 만료하기위해 직접 DB에 토큰을 넣는 방식을 썼는데, 시스템적 손해가 크기 때문에 잘못된 방법이기도 했다. 또한 RefreshToken을 발급하는 과정또한 존재하지 않았기 때문에 제대로 된 로그인 시스템을 구축했다고 보기 어려웠다. 그러다 보니 사용자의 계정을 인증하는 방법에 대해서 다시 공부를 하였고 제대로 된 로직을 설계하고 다시 한번 회원가입, 로그인, 토큰 재발급, 로그아웃의 서비스들을 개발했으며 개발한 코드의 이해력을 높이기 위해 글을 작성하려 한다.

사실 회원가입 / 로그인 / 토큰 재발급 / 로그아웃만 하더라도 꽤나 복잡하다, 물론 계정에 대한 보안과 밀접한 관련이 있기 때문에 더 복잡하겠지만 양이 생각보다 많아서 여러 편으로 나눠서 글을 작성할 예정이다. 그래서 오늘은 회원가입 로직에 대해서 작성해보려 한다.

그전에 AccessToken과 RefreshToken에 대한 선수 개념이 부족하다면 아래 사이트를 참고해 개념과 왜 사용하는지에 대해 이해를 하는 것이 중요하다.

🤔 이 글은 JWT에 대한 기초지식이 필요합니다!
참조 : Access Token과 Refresh Token 원리

1. 진행


회원가입 로직
1. 서버에서 사용의 닉네임, 이메일, 비밀번호를 요청
2. 요청받은 값과 유저 권한을 설정해 DB에 저장
3. 유저의 이메일과 비밀번호를 이용해 Authentication에 저장
4. SeucurityContextHolder에 Authentication을 저장
5. Authentication의 담긴 정보를 통해 AccessToken 발급
6. 권한 정보가 담아져있지 않은 RefreshToken 발급
7. Redis를 이용해 [ 사용자의 이메일 : RefreshToken ] 형태로 인메모리 데이터에 저장

위의 로직을 토대로 회원가입 서비스를 개발하는데 다만 SpringSecurity의 Filter와 Jwt 관련 Config 클래스는 양이 워낙 많은 관계로 생략하고 서비스 위주의 코드를 살펴보도록 하겠다.

Jwt와 기타 Config는 위의 패키지 구조로 대체하며, 이 정도가 들어갔다 정도만 글에 작성하겠다,, 다만 서비스 로직에서 중요하게 여겨지는 부분은 다루도록 하겠다.

아래 부분을 통해 먼저 Redis를 사용하기위해 세팅해주자

Redis 기본 세팅 방법 ➡️ Redis 사용 및 활용하여 게시글 조회수 구현하기

1. Service class

위에 미리 서술해둔 회원가입 로직을 토대로 짜인 코드이다.

JPA를 이용해 사용자의 데이터를 저장해주었는데, 이때 authorities에 유저의 권한을 저장해주었다. 그 이후 authentication에 사용자의 이메일과 비밀번호를 저장하고 authentication을 SecurityContextHolder에 저장해주었다.

tokenProvider.createToken(authentication)

public String createToken(Authentication authentication) {
    String authorities = authentication.getAuthorities().stream()
            .map(GrantedAuthority::getAuthority)
            .collect(Collectors.joining(","));

    long now = (new Date()).getTime();
    Date validity = new Date(now + this.tokenValidityInMilliseconds);

    return Jwts.builder()
            .setSubject(authentication.getName())
            .claim(AUTHORITIES_KEY, authorities)
            .signWith(key, SignatureAlgorithm.HS512)
            .setExpiration(validity)
            .compact();
}

TokenProvider의 createToke을 통해 AccessToken을 생성해주었으며 이는 권한 정보와 사용자의 정보 / 토큰의 유효시간 등을 설정해주었다.

tokenProvider.createRefreshToken(request.getEmail())

public String createRefreshToken(String username) {
    long now = (new Date()).getTime();
    Date validity = new Date(now + this.refreshTokenValidityInMilliseconds);
    return Jwts.builder()
            .setSubject(username)
            .setExpiration(validity)
            .signWith(key, SignatureAlgorithm.HS512)
            .compact();
}

또한 refreshToken의 경우 사용자의 권한 정보를 담지 않고 생성해주었으며 유효시간을 길게 잡아주었다. 토큰을 생성하면서 헷갈렸던 점은 setExpiration의 경우 밀리 세컨드로 저장해주어야 하기 때문에 시간 변환을 꼭 해주도록 하자.

마지막으로 redisDao를 통해서 유저의 이메일을 key값으로 지정하여 value값을 refreshToken으로 저장 후 14일 동안 지속되게끔 만들어주었다. Spring에서 redis를 사용하는 방법은 여러 가지가 있기 때문에 개발자가 편한 대로 redis를 이용하여 값을 저장하면 될 것이다.

저장된 refreshToken을 통해 추후 AccessToken 재발급을 해야 할 때 검증을 할 것 이기 때문에 필수로 거쳐야 하는 로직이다.

2. 마무리


나중에 Validation의 검증을 위해 간단하게 회원정보를 읽어오는 Service를 개발할 것인데 이때 AccessToken을 통해 사용자의 인증 상태를 확인하는 로직을 확인해보도록 하자 👍

profile
내가 몰입하는 과정을 담은 곳

0개의 댓글