SKKUNION - SpringSecurity 설명 1

2023. 11. 3. 20:18팀프로젝트일기/SKKUNION

 글을 오랜만에 쓰는데, Security 설정대로 사용하시려면 4가지 파일을 정확하게 이해하고 계시면 편합니다! security 폴더 내부에 있는 WebSecurityConfig, SecurityUtil랑 jwt 폴더 내부에 있는 JwtTokenProvide, service 폴더 내부에 있는 CustomUserDetailService를 아시면 편합니다!

 

WebSecurityConfig

 여기를 아는 게 제일 중요할 것 같아요. 왜 본인이 잘하시다가 Postman으로 Request를 보냈는데 400 뜨는 경우에 뭔 원인인지 모르실 때 이 부분을 체크해주세요.

 

 아래를 보시면 antMatchers라는 부분으로 경로와 permitAll 같은 게 있는데 이 말은 이 프로젝트로 만들어진 서버의 응답에서 해당 경로로 오는 경우, Security 확인 없이 넘긴다는 의미입니다. 일단은 적용된 걸 처리하기 전까진 전부 열어둘게요.

 

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
                .httpBasic().disable() // rest api만을 고려한 설계
                .csrf().disable() // csrf 보안 토큰 disable
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //토큰 기반 인증 방식이라 세션 비활성화
                .and()
                .authorizeRequests()
                .antMatchers("/api/**/**").permitAll() // login 관련은 인증이 필요없음
                .and()
                .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
                        UsernamePasswordAuthenticationFilter.class);
    }

 

 

JwtTokenProvider

 해당 부분에 들어가면 여기가 제일 기능이 많은데 AccessToken이랑 RefreshToken을 둘 다 쓰기로 했었거든요? 그래서 간단하게 과정을 설명하면, 로그인이 되면 AccessToken이랑 RefreshToken을 발급해주고 이제 서버에서는 AccessToken을 매번 요청 때마다 보내주고 그 정보 내에는 유저 ID, PW, 권한 정보가 들어있어서 그거에 따라 확인하시면 됩니다. 그리고 AccessToken을 1시간으로 해놨는데 해당 만료되면 RefreshToken보고 재발급해주는 형태입니다.

 

출처: spring security + JWT 로그인 기능 파헤치기 - 1 (tistory.com)

 

spring security + JWT 로그인 기능 파헤치기 - 1

로그인 기능은 거의 대부분의 애플리케이션에서 기본적으로 사용됩니다. 추가로 요즘은 웹이 아닌 모바일에서도 사용 가능하다는 장점과 Stateless 한 서버 구현을 위해 JWT를 사용하는 경우를 많

wildeveloperetrain.tistory.com

 

일단 JwtTokenProvider에서 확인해주실 건  validateToken에서 false가 나왔다는 건 뭔가 중간에 짤렸건 만료되었건 이상한 형식으로 보낸건데 이 부분은 2에서 다시 설명을 드리겠습니다.

 

    // 토큰 정보를 검증하는 메서드
    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(key).parseClaimsJws(token);
            return true;
        } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
            log.info("Invalid JWT Token", e);
        } catch (ExpiredJwtException e) {
            log.info("Expired JWT Token", e);
        } catch (UnsupportedJwtException e) {
            log.info("Unsupported JWT Token", e);
        } catch (IllegalArgumentException e) {
            log.info("JWT claims string is empty.", e);
        }
        return false;
    }

 

 

그리고 이제 계정에 있어서 admin과 일반 유저를 구분해야 하잖아요? 그 때는 일단 ADMIN 회원가입이랑 USER 회원가입이랑 분리해서 하라고 하셨으니까 둘 다 분리해서 ADMIN인지 가입하는거로 만들어놨고요. 둘 다 똑같은데 권한이 달라요. 권한을 가져오는 방법도 JwtTokenProvider에 있습니다.

 

 

 

    // JWT 토큰을 복호화하여 토큰에 들어있는 정보를 꺼내는 메서드
        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);
        }

 

 이 부분인데요. 가져오는 예시를 보고 싶으시면 해당 함수로 가져오셔서 Authentication 객체를 받아오신 다음에 Authentication 객체에서 getAuthority 함수를 통해서 가져오시면 ADMIN과 USER로 나뉘어져있을거에요! 그거로 사용하시면 됩니다.