일단 로그인 구현해보기

이름이름·2023년 2월 10일
0

프로젝트 Lionz

목록 보기
3/10
post-thumbnail

어차피 따라한거지만 복잡해서 까먹을까봐 적어놓는 구현흐름
장고했을때 회원가입 + 로그인 구현하는것은 그렇게 복잡하지 않았던 것으로 기억한다. 하지만 스프링 하면서 로그인을 해보려니 너무 복잡하고 어려웠다..
버전 신경써야하고 deprecated된 것들이 꽤 많아서 애를 먹었다.

구글링해도 괜찮은 참고자료를 찾기 어려웠는데 우연히
https://velog.io/@tank3a/Security-%EC%84%A4%EC%A0%951
를 알게되었고 이 분을 통해 아래링크의 블로그를 알게되었다

https://bcp0109.tistory.com/301
이 블로그가 최고인것같다

폴더 구조

우선 현재 폴더구조는 아래와 같다

원래 하던 프로젝트에 로그인을 구현하기위해 추가한것 들이 많아 무엇을 추가했었는지 작성하도록 하겠다

의존성 추가 (build.gradle)

처음에 프로젝트를 만들 때 추가하지 않았어서 수동으로 추가해줬다

dependencies{
	//스프링 시큐리티
	implementation 'org.springframework.boot:spring-boot-starter-security'

	//JWT
	implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2'
	runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
	runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'

application.yml

jwt:         
  secret: ~~~~

domain

Member

원래 나는 회원을 User로 했었다.
하지만 스프링 시큐리티 자체적으로 UserDetails 의 구현체인 User 를 사용하기 때문에 헷갈리지 않도록 Account 또는 Member 로 이름 짓는게 좋다고 한다.
(처음 알게되었는데 import할 때 진짜 있긴했었다)

결론 : User라는 이름은 웬만해서는 피하는게 좋다. 실제로 import할 때 무지성 option+enter로 추가하다가 내가 domain에 만들어놓은 User 엔티티를 추가한적이 있다

RefreshToken

리프레시 토큰 저장하는 엔티티

Member
Member Reposity
Member Service 를 각각 구현해준다

JWT

TokenProvider
JwtFilter
JwtSecurityConfig
JwtAuthenticationEntryPoint
JwtAccessDeniedHandler
구현해준다

TokenProvider 속 에러들

signWith()

// Access Token 생성
	Date accessTokenExpiresIn = new Date(now + ACCESS_TOKEN_EXPIRE_TIME);
        String accessToken = Jwts.builder()
                .setSubject(authentication.getName())       // payload "sub": "name"
                .claim(AUTHORITIES_KEY, authorities)        // payload "auth": "ROLE_USER"
                .setExpiration(accessTokenExpiresIn)        // payload "exp": 1516239022 (예시)
                .signWith(SignatureAlgorithm.HS512, key)    // header "alg": "HS512"
                .compact();
               

원래는 위에 .signWith() 안에 key랑 SignatureAlgorithm.HS512가 반대로 되어있었는데 위에처럼 해주니까 에러가 사라짐
https://leeeehhjj.tistory.com/m/61
이분거 보고 참고한건데 이분은 또 나랑 반대로 하니까 됐다고 하신다..
그리고 .signWith 자체가 deprecated 됐다고 하는것 같다





SimpleGrantedAuthority

  public Authentication getAuthentication(String accessToken) {
        // 토큰 복호화
        Claims claims = parseClaims(accessToken);

        if (claims.get(AUTHORITIES_KEY) == null) {
            throw new RuntimeException("권한 정보가 없는 토큰입니다.");
        }

        // 클레임에서 권한 정보 가져오기
        Collection<? extends GrantedAuthority> authorities =
                Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
                        .map(SimpleGrantedAuthority::new)
                        .collect(Collectors.toList());

        // UserDetails 객체를 만들어서 Authentication 리턴
        UserDetails principal = new User(claims.getSubject(), "", authorities);

        return new UsernamePasswordAuthenticationToken(principal, "", authorities);
    }

그리고 또 위에보면 중간에 SimpleGrantedAuthority가 있는데
저거는 추가하라는 메시지가 안떠가지고 아래 것 직접 import해줌

import org.springframework.security.core.authority.SimpleGrantedAuthority;

Config

JwtSecurityConfig
SecurityConfig

Util

SecurityUtil

Repository

MemberReposity
RefreshTokenRepository (리프레시 토큰 저장소)

Service

MemberService
AuthService
CustomUserDetailsService

API (or Controller)

AuthController
MemberController

dto (API안 패키지)

MemberRequestDto
MemberResponseDto
TokenDto
TokenRequestDto

profile
공부 정리

0개의 댓글