Java/인증 및 인가, IAM

[Java] Spring Boot Security 이해하기 -4: JWT 환경 설정 및 구성 하기

adjh54 2023. 1. 1. 17:44
728x170
해당 글에서는 Spring Boot Security내에 ‘인증’ 방식을 JWT를 이용하여서 사용자의 인증을 구성하는 환경 설정방법에 대해서 이해하기 위한 글입니다.

 

 

 

 

 

 

💡 [참고] 해당 글은 이전에 작성한 'JWT 이론'에 대해서 이해를 하고 구성을 하시면 크게 도움이 됩니다
 

[Java] Spring Boot Security 이해하기 -3: JWT(JSON Web Token) 이해하기

해당 글에서는 Spring Security의 인증을 위한 ‘JWT: JSON Web Token’를 이해하고 적용하기 위해 우선 이해를 목적으로 작성한 글입니다. 추후 적용을 위한 환경 설정 방법에 대해서 공유합니다. [참고]

adjh54.tistory.com

 

 

 

1) 개발 환경 


💡 Spring Security & JWT 개발 환경을 구성하기 위해 사용한 개발환경입니다.
개발 환경 버전 비고 
java 11  
Spring Boot 2.7.5  
Spring Boot Starter Security 2.7.5 Spring Framework : 5.7.4
io.jsonwebtoken:jjwt 0.9.1  
Spring Boot Starter Data JDBC 2.7.5  
mybatis 2.2.2  
lombok latest  
postgresql latest  
빌드관리도구 Gradle 7.5  
개발 툴 IntelliJ IDEA 2022.3  
API 테스트 툴 Postman  

 

 

 

 

2) JWT 환경 설정하기


1. build.gradle 라이브러리 추가


💡build.gradle 라이브러리 추가

- 빌드 관리 도구로 ‘Gradle’을 이용하여서 주요 라이브러리를 추가하였습니다.
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'          // Spring Security
    implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'         // Spring Boot JDBC + HikariCP
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2'      // Spring Boot MyBatis
    implementation "io.jsonwebtoken:jjwt:0.9.1"                                     // Spring Json-Web-Token
    compileOnly 'org.projectlombok:lombok'                                          // Lombok
    runtimeOnly 'org.postgresql:postgresql'                                         // PostgreSQL
}

 

 

 

2. WebSecurityConfig.java


💡 WebSecurityConfig.java

-
Spring Security의 환경설정을 구성하기 위한 클래스입니다.

- 웹 서비스가 로드될 때 Spring Container에 의해 관리가 되는 클래스이며 사용자에 대한 ‘인증’과 ‘인가’에 대한 구성을 Bean 메서드로 주입을 합니다. 추가로 JWT 처리를 위한 Filter를 @Bean으로 등록하였습니다.


💡 JWT를 구성하기 위해서 사용된 부분

- 해당 주석 중 2번에 [STEP3]에서 해당 ‘JWT 필터’를 등록합니다.
- 해당 주석 중 9번에 JwtAuthorizationFilter() 클래스를 참조합니다.

 

package com.adjh.multiflexapi.config;

import com.adjh.multiflexapi.config.filter.CustomAuthenticationFilter;
import com.adjh.multiflexapi.config.filter.JwtAuthorizationFilter;
import com.adjh.multiflexapi.config.handler.CustomAuthFailureHandler;
import com.adjh.multiflexapi.config.handler.CustomAuthSuccessHandler;
import com.adjh.multiflexapi.config.handler.CustomAuthenticationProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

/**
 * Spring Security 환경 설정을 구성하기 위한 클래스입니다.
 * 웹 서비스가 로드 될때 Spring Container 의해 관리가 되는 클래스이며 사용자에 대한 ‘인증’과 ‘인가’에 대한 구성을 Bean 메서드로 주입을 한다.
 */
@Slf4j
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    /**
     * 1. 정적 자원(Resource)에 대해서 인증된 사용자가  정적 자원의 접근에 대해 ‘인가’에 대한 설정을 담당하는 메서드이다.
     *
     * @return WebSecurityCustomizer
     */
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        // 정적 자원에 대해서 Security를 적용하지 않음으로 설정
        return web -> web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations());
    }

    /**
     * 2. HTTP에 대해서 ‘인증’과 ‘인가’를 담당하는 메서드이며 필터를 통해 인증 방식과 인증 절차에 대해서 등록하며 설정을 담당하는 메서드이다.
     *
     * @param http HttpSecurity
     * @return SecurityFilterChain
     * @throws Exception Exception
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        log.debug("[+] WebSecurityConfig Start !!! ");

        http
                // [STEP1] 서버에 인증정보를 저장하지 않기에 csrf를 사용하지 않는다.
                .csrf().disable()

                // [STEP2] 토큰을 활용하는 경우 모든 요청에 대해 '인가'에 대해서 적용
                .authorizeHttpRequests(authz -> authz.anyRequest().permitAll())

                // [STEP3] Spring Security JWT Filter Load
                .addFilterBefore(jwtAuthorizationFilter(), BasicAuthenticationFilter.class)

                // [STEP4] Session 기반의 인증기반을 사용하지 않고 추후 JWT를 이용하여서 인증 예정
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()
                // [STEP5] form 기반의 로그인에 대해 비 활성화하며 커스텀으로 구성한 필터를 사용한다.
                .formLogin().disable()

                // [STEP6] Spring Security Custom Filter Load - Form '인증'에 대해서 사용
                .addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        // [STEP7] 최종 구성한 값을 사용함.
        return http.build();
    }

    /**
     * 3. authenticate 의 인증 메서드를 제공하는 매니져로'Provider'의 인터페이스를 의미합니다.
     * - 과정: CustomAuthenticationFilter → AuthenticationManager(interface) → CustomAuthenticationProvider(implements)
     *
     * @return AuthenticationManager
     */
    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(customAuthenticationProvider());
    }

    /**
     * 4. '인증' 제공자로 사용자의 이름과 비밀번호가 요구됩니다.
     * - 과정: CustomAuthenticationFilter → AuthenticationManager(interface) → CustomAuthenticationProvider(implements)
     *
     * @return CustomAuthenticationProvider
     */
    @Bean
    public CustomAuthenticationProvider customAuthenticationProvider() {
        return new CustomAuthenticationProvider(bCryptPasswordEncoder());
    }

    /**
     * 5. 비밀번호를 암호화하기 위한 BCrypt 인코딩을 통하여 비밀번호에 대한 암호화를 수행합니다.
     *
     * @return BCryptPasswordEncoder
     */
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 6. 커스텀을 수행한 '인증' 필터로 접근 URL, 데이터 전달방식(form) 등 인증 과정 및 인증 후 처리에 대한 설정을 구성하는 메서드입니다.
     *
     * @return CustomAuthenticationFilter
     */
    @Bean
    public CustomAuthenticationFilter customAuthenticationFilter() {
        CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter(authenticationManager());
        customAuthenticationFilter.setFilterProcessesUrl("/api/v1/user/login");     // 접근 URL
        customAuthenticationFilter.setAuthenticationSuccessHandler(customLoginSuccessHandler());    // '인증' 성공 시 해당 핸들러로 처리를 전가한다.
        customAuthenticationFilter.setAuthenticationFailureHandler(customLoginFailureHandler());    // '인증' 실패 시 해당 핸들러로 처리를 전가한다.
        customAuthenticationFilter.afterPropertiesSet();
        return customAuthenticationFilter;
    }

    /**
     * 7. Spring Security 기반의 사용자의 정보가 맞을 경우 수행이 되며 결과값을 리턴해주는 Handler
     *
     * @return CustomLoginSuccessHandler
     */
    @Bean
    public CustomAuthSuccessHandler customLoginSuccessHandler() {
        return new CustomAuthSuccessHandler();
    }

    /**
     * 8. Spring Security 기반의 사용자의 정보가 맞지 않을 경우 수행이 되며 결과값을 리턴해주는 Handler
     *
     * @return CustomAuthFailureHandler
     */
    @Bean
    public CustomAuthFailureHandler customLoginFailureHandler() {
        return new CustomAuthFailureHandler();
    }

    /**
     * 9. JWT 토큰을 통하여서 사용자를 인증합니다.
     *
     * @return JwtAuthorizationFilter
     */
    @Bean
    public JwtAuthorizationFilter jwtAuthorizationFilter() {
        return new JwtAuthorizationFilter();
    }

}

 

 

 

3. AuthConstants.java


💡 AuthConstants.java

- 해당 클래스는 상수로 정의한 파일이며 JWT 토큰에서 Header에 키 값으로 사용되는 authorization 값과 클라이언트에서 JWT로 전송을 할 때 사용하는 “BEARER” 값을 상수로 정의하였습니다.
package com.adjh.multiflexapi.common.codes;

/**
 * JWT 관련된 상수로 사용 되는 파일
 *
 * @author lee
 * @fileName AuthConstants
 * @since 2022.12.23
 */
public final class AuthConstants {
    public static final String AUTH_HEADER = "Authorization";
    public static final String TOKEN_TYPE = "BEARER";
}

 

 

 

4. TokenUtil.java


💡TokenUtil.java

- 해당 클래스는 JWT에서 사용되는 토큰 관련 유틸들을 관리하는 클래스입니다.
- JWT를 생성하거나 유효성을 체크하는 등의 전반적으로 처리되는 기능들을 모아둔 클래스입니다.

- 해당 부분 중 private static final String jwtSecretKey로 Secret 키를 지정한 부분이 있습니다. 예시를 위해서 선언하였지만, 보안적인 이슈를 생각하여 환경파일 내에 넣어두고 별도로 관리하며 사용하는 것을 권장드립니다.
package com.adjh.multiflexapi.common.utils;

import com.adjh.multiflexapi.model.UserDto;
import io.jsonwebtoken.*;
import lombok.extern.log4j.Log4j2;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT 관련된 토큰 Util
 *
 * @author lee
 * @fileName TokenUtils
 * @since 2022.12.23
 */
@Log4j2
public class TokenUtils {

    //    @Value(value = "${custom.jwt-secret-key}")
    private static final String jwtSecretKey = "exampleSecretKey";

    /**
     * 사용자 정보를 기반으로 토큰을 생성하여 반환 해주는 메서드
     *
     * @param userDto UserDto : 사용자 정보
     * @return String : 토큰
     */
    public static String generateJwtToken(UserDto userDto) {
        // 사용자 시퀀스를 기준으로 JWT 토큰을 발급하여 반환해줍니다.
        JwtBuilder builder = Jwts.builder()
                .setHeader(createHeader())                              // Header 구성
                .setClaims(createClaims(userDto))                       // Payload - Claims 구성
                .setSubject(String.valueOf(userDto.getUserSq()))        // Payload - Subject 구성
                .signWith(SignatureAlgorithm.HS256, createSignature())  // Signature 구성
                .setExpiration(createExpiredDate());                    // Expired Date 구성
        return builder.compact();
    }

    /**
     * 토큰을 기반으로 사용자 정보를 반환 해주는 메서드
     *
     * @param token String : 토큰
     * @return String : 사용자 정보
     */
    public static String parseTokenToUserInfo(String token) {
        return Jwts.parser()
                .setSigningKey(jwtSecretKey)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    /**
     * 유효한 토큰인지 확인 해주는 메서드
     *
     * @param token String  : 토큰
     * @return boolean      : 유효한지 여부 반환
     */
    public static boolean isValidToken(String token) {
        try {
            Claims claims = getClaimsFormToken(token);

            log.info("expireTime :" + claims.getExpiration());
            log.info("userId :" + claims.get("userId"));
            log.info("userNm :" + claims.get("userNm"));

            return true;
        } catch (ExpiredJwtException exception) {
            log.error("Token Expired");
            return false;
        } catch (JwtException exception) {
            log.error("Token Tampered");
            return false;
        } catch (NullPointerException exception) {
            log.error("Token is null");
            return false;
        }
    }

    /**
     * Header 내에 토큰을 추출합니다.
     *
     * @param header 헤더
     * @return String
     */
    public static String getTokenFromHeader(String header) {
        return header.split(" ")[1];
    }

    /**
     * 토큰의 만료기간을 지정하는 함수
     *
     * @return Calendar
     */
    private static Date createExpiredDate() {
        // 토큰 만료시간은 30일으로 설정
        Calendar c = Calendar.getInstance();
        c.add(Calendar.HOUR, 8);     // 8시간
        // c.add(Calendar.DATE, 1);         // 1일
        return c.getTime();
    }

    /**
     * JWT의 "헤더" 값을 생성해주는 메서드
     *
     * @return HashMap<String, Object>
     */
    private static Map<String, Object> createHeader() {
        Map<String, Object> header = new HashMap<>();

        header.put("typ", "JWT");
        header.put("alg", "HS256");
        header.put("regDate", System.currentTimeMillis());
        return header;
    }

    /**
     * 사용자 정보를 기반으로 클래임을 생성해주는 메서드
     *
     * @param userDto 사용자 정보
     * @return Map<String, Object>
     */
    private static Map<String, Object> createClaims(UserDto userDto) {
        // 공개 클레임에 사용자의 이름과 이메일을 설정하여 정보를 조회할 수 있다.
        Map<String, Object> claims = new HashMap<>();

        log.info("userId :" + userDto.getUserId());
        log.info("userNm :" + userDto.getUserNm());

        claims.put("userId", userDto.getUserId());
        claims.put("userNm", userDto.getUserNm());
        return claims;
    }

    /**
     * JWT "서명(Signature)" 발급을 해주는 메서드
     *
     * @return Key
     */
    private static Key createSignature() {
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(jwtSecretKey);
        return new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
    }

    /**
     * 토큰 정보를 기반으로 Claims 정보를 반환받는 메서드
     *
     * @param token : 토큰
     * @return Claims : Claims
     */
    private static Claims getClaimsFormToken(String token) {
        return Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(jwtSecretKey))
                .parseClaimsJws(token).getBody();
    }

    /**
     * 토큰을 기반으로 사용자 정보를 반환받는 메서드
     *
     * @param token : 토큰
     * @return String : 사용자 아이디
     */
    public static String getUserIdFromToken(String token) {
        Claims claims = getClaimsFormToken(token);
        return claims.get("userId").toString();
    }
}

 

 

 

 

5. JwtAuthorizationFilter.java


💡JwtAuthorizationFilter.java

- 해당 클래스는 Spring Security의 환경설정을 구성하는 단계에서 필터로 등록한 클래스이며, 지정한 URL 별 JWT 유효성 검증을 수행하며 직접적인 사용자 '인증' (*STEP6 참고)을 확인합니다.
package com.adjh.multiflexapi.config.filter;

import com.adjh.multiflexapi.common.codes.AuthConstants;
import com.adjh.multiflexapi.common.codes.ErrorCode;
import com.adjh.multiflexapi.common.utils.TokenUtils;
import com.adjh.multiflexapi.config.exception.BusinessExceptionHandler;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.SignatureException;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.json.simple.JSONObject;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * 지정한 URL 별 JWT 유효성 검증을 수행하며 직접적인 사용자 '인증'을 확인합니다.
 *
 * @author lee
 * @fileName JwtAuthorizationFilter
 * @since 2022.12.23
 */
@Slf4j
@Component
public class JwtAuthorizationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain chain)
            throws IOException, ServletException {

        // 1. 토큰이 필요하지 않은 API URL에 대해서 배열로 구성합니다.
        List<String> list = Arrays.asList(
                "/api/v1/user/login",
                "/api/v1/test/generateToken"
//                "api/v1/code/codeList"
        );

        // 2. 토큰이 필요하지 않은 API URL의 경우 => 로직 처리 없이 다음 필터로 이동
        if (list.contains(request.getRequestURI())) {
            chain.doFilter(request, response);
            return;
        }

        // 3. OPTIONS 요청일 경우 => 로직 처리 없이 다음 필터로 이동
        if (request.getMethod().equalsIgnoreCase("OPTIONS")) {
            chain.doFilter(request, response);
            return;
        }

        // [STEP1] Client에서 API를 요청할때 Header를 확인합니다.
        String header = request.getHeader(AuthConstants.AUTH_HEADER);
        logger.debug("[+] header Check: " + header);

        try {
            // [STEP2-1] Header 내에 토큰이 존재하는 경우
            if (header != null && !header.equalsIgnoreCase("")) {

                // [STEP2] Header 내에 토큰을 추출합니다.
                String token = TokenUtils.getTokenFromHeader(header);

                // [STEP3] 추출한 토큰이 유효한지 여부를 체크합니다.
                if (TokenUtils.isValidToken(token)) {

                    // [STEP4] 토큰을 기반으로 사용자 아이디를 반환 받는 메서드
                    String userId = TokenUtils.getUserIdFromToken(token);
                    logger.debug("[+] userId Check: " + userId);

                    // [STEP5] 사용자 아이디가 존재하는지 여부 체크
                    if (userId != null && !userId.equalsIgnoreCase("")) {
                        
                        // TODO: [STEP6] 실제 DB로 조회를 하여 유효한 사용자 인지 확인(인증)하는 부분이 들어가면 될것 같습니다. 
                        chain.doFilter(request, response);
                    } else {
                        throw new BusinessExceptionHandler("TOKEN isn't userId", ErrorCode.BUSINESS_EXCEPTION_ERROR);
                    }
                    // 토큰이 유효하지 않은 경우
                } else {
                    throw new BusinessExceptionHandler("TOKEN is invalid", ErrorCode.BUSINESS_EXCEPTION_ERROR);
                }
            }
            // [STEP2-1] 토큰이 존재하지 않는 경우
            else {
                throw new BusinessExceptionHandler("Token is null", ErrorCode.BUSINESS_EXCEPTION_ERROR);
            }
        } catch (Exception e) {
            // Token 내에 Exception이 발생 하였을 경우 => 클라이언트에 응답값을 반환하고 종료합니다.
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            PrintWriter printWriter = response.getWriter();
            JSONObject jsonObject = jsonResponseWrapper(e);
            printWriter.print(jsonObject);
            printWriter.flush();
            printWriter.close();
        }
    }

    /**
     * 토큰 관련 Exception 발생 시 예외 응답값 구성
     *
     * @param e Exception
     * @return JSONObject
     */
    private JSONObject jsonResponseWrapper(Exception e) {

        String resultMsg = "";
        // JWT 토큰 만료
        if (e instanceof ExpiredJwtException) {
            resultMsg = "TOKEN Expired";
        }
        // JWT 허용된 토큰이 아님
        else if (e instanceof SignatureException) {
            resultMsg = "TOKEN SignatureException Login";
        }
        // JWT 토큰내에서 오류 발생 시
        else if (e instanceof JwtException) {
            resultMsg = "TOKEN Parsing JwtException";
        }
        // 이외 JTW 토큰내에서 오류 발생
        else {
            resultMsg = "OTHER TOKEN ERROR";
        }

        HashMap<String, Object> jsonMap = new HashMap<>();
        jsonMap.put("status", 401);
        jsonMap.put("code", "9999");
        jsonMap.put("message", resultMsg);
        jsonMap.put("reason", e.getMessage());
        JSONObject jsonObject = new JSONObject(jsonMap);
        logger.error(resultMsg, e);
        return jsonObject;
    }
}

 

 

 

 

 

 

4) 전송 테스트 : 토큰 발급


 

1. TestController.java


💡 사전에 구성한 TokenUtils의 generateJwtToken 함수를 통해서 JWT를 발급받습니다.
package com.adjh.multiflexapi.controller;

import com.adjh.multiflexapi.common.codes.AuthConstants;
import com.adjh.multiflexapi.common.codes.SuccessCode;
import com.adjh.multiflexapi.common.response.ApiResponse;
import com.adjh.multiflexapi.common.utils.TokenUtils;
import com.adjh.multiflexapi.model.UserDto;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("api/v1/test")
public class TestController {

    /**
     * [API] 사용자 정보를 기반으로 JWT를 발급하는 API
     *
     * @param userDto UserDto
     * @return ApiResponseWrapper<ApiResponse> : 응답 결과 및 응답 코드 반환
     */
    @PostMapping("/generateToken")
    @Operation(summary = "토큰 발급", description = "사용자 정보를 기반으로 JWT를 발급하는 API")
    public ResponseEntity<ApiResponse> selectCodeList(@RequestBody UserDto userDto) {

        String resultToken = TokenUtils.generateJwtToken(userDto);

        ApiResponse ar = ApiResponse.builder()
                // BEARER {토큰} 형태로 반환을 해줍니다.
                .result(AuthConstants.TOKEN_TYPE + " " + resultToken)
                .resultCode(SuccessCode.SELECT.getStatus())
                .resultMsg(SuccessCode.SELECT.getMessage())
                .build();

        return new ResponseEntity<>(ar, HttpStatus.OK);
    }

}

 

[참고] 사전에 필터 내에 토큰 처리를 제외할 URL을 정의하였습니다.

 

 

2. API 호출


💡 구성한 API를 호출하여서 JWT 값을 반환받았습니다.

 

 

3. 유효한 토큰 확인


[참고] 공식사이트 - JWT debug
 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

 

💡 인코딩 된 토큰 값을 좌측에 넣어보면 발급한 사용자 정보가 오른쪽에 출력이 됩니다.

 

💡 토큰 생성 시 넣어둔 값의 유효성을 확인하고 내용도 확인하였습니다. 

 

 

 

 

5) 전송 테스트 -1 : 토큰 미 존재 시


 

1. JWT 값을 넣지 않고 API 통신 시 테스트


💡 토큰이 존재하지 않는다고 수행됩니다.

 

 

 

 

6) 전송 테스트 -2 : 토큰 존재 시


 

1. 필터 확인


💡 해당 필터에서 토큰을 제외하는 URL로 빼두지 않은 상태입니다.

 

 

2. 발급받은 토큰값을 Header에 넣어둡니다.


💡 Postman의 Authorization 탭에서 ‘Bearer Token’을 선택하고 발급받은 토큰 값을 넣어줍니다.

 

 

3. API를 호출합니다.


💡 결과값을 잘 반환해 주는 것을 확인하였습니다.

 

 

4. Token을 빼고 API를 호출합니다.


💡 토큰을 빼고 API를 호출하는 경우 토큰이 존재하지 않음을 반환해주고 있습니다.

 

 

[참고] 해당 환경을 구성하기 위해 작성한 사전글에 대해서 공유합니다.
 

[Java] Spring Boot Security 이해하기 -1 : 5.7.x 버전 구조 및 파일 이해

해당 글에서는 Spring Boot 기반의 Spring Security Framework를 적용하여 로그인의 API를 구성하는 방법에 대해서 공유합니다. 1) 개발환경 💡 Spring Security 개발 환경을 구성하기 위해 사용한 개발환경입니

adjh54.tistory.com

 

[Java] Spring Boot Security 이해하기 -2 : 5.7.x 버전 구현하기

해당 글에서는 이전에 Spring Security 5.7.x 버전에 대해 이해한 내용을 기반으로 실제 구현하는 방법에 대해서 공유합니다. [참고] Spring Boot Security를 적용하기 이전의 이해하기 위한 글을 참고하시

adjh54.tistory.com

 

[Java] Spring Boot Security 이해하기 -3: JWT(JSON Web Token) 이해하기

해당 글에서는 Spring Security의 인증을 위한 ‘JWT: JSON Web Token’를 이해하고 적용하기 위해 우선 이해를 목적으로 작성한 글입니다. 추후 적용을 위한 환경 설정 방법에 대해서 공유합니다. [참고]

adjh54.tistory.com

 

[참고] 해당 글을 기반으로 구성한 Git Repository입니다.
 

blog-codes/spring-boot2-security at main · adjh54ir/blog-codes

Contributor9 티스토리 블로그 내에서 활용한 내용들을 담은 레포지토리입니다. Contribute to adjh54ir/blog-codes development by creating an account on GitHub.

github.com

 

 

 

 

 

 

 

오늘도 감사합니다 😄

 

 

 

 

 

그리드형