💬
목차
< 뒤로가기
인쇄

캐모마일 시큐리티(JWT) 가이드

시큐리티 (JWT)

본 문서에서는 웹사이트에서 사용하는 JWT(Java Web Token) 기반 시큐리티를 사용하기 위한 기능에 대해 설명한다.

  • 인증(Authentication)과 인가(Authorization)에 대한 세부 내용은 세션 기반 캐모마일 시큐리티 문서를 참고한다.

관련 주요 클래스

클래스/컴포넌트명 설명
ChamomileSecurityJwtConfiguration.java JWT 기반 캐모마일 시큐리티 설정을 관리
AccessTokenFilter.java 최초 로그인 시 사용자 인증 및 토큰을 발급(access, refresh)하여 DB 또는 캐시에 저장
RefreshTokenFilter.java RefreshToken을 통해 AccessToken과 RefreshToken을 재발급
JwtFilter.java API 인증 시 토큰 유효성을 검사하며, 실제 사용자 인증은 프로바이더에게 위임
JwtProvider.java 사용자 정보와 토큰을 검증해 실제 인증 과정을 처리
JwtTokenUtils.java Jwt토큰 생성,삭제, 유효성 등 JWT 관련된 전반적인 유틸
JwtAuthentication.java AccessToken, RefreshToken, Validate 등의 과정을 담당

토큰 발급(로그인 요청)

  • AccessToken

    • 목적: 클라이언트가 API 요청 시 사용된다.
    • 특징
      • 유효 기간이 짧다 (기본 30분).
      • application.yml에서 유효 기간 조정 가능.
      • 만료 후, RefreshToken을 사용해 재발급 가능하다.
  • RefreshToken

    • 목적: AccessToken이 만료되었을 때 새로운 AccessToken, RefreshToken을 발급 받기 위해 사용된다.
    • 특징:
      • AccessToken보다 긴 유효 기간을 가진다 (기본 1일).
      • 재발급시 AccessToken, RefreshToken 함께 새로 발급 된다.
  • 발급 절차

    • 입력 받은 ID 와 Password를 전달 받아 비밀번호 및 사용자 정보 검증 후 AccessToken 과 함께 RefreshToken을 발급한다.
    • /security/jwt/authenticate로 요청을 보내면 JSON {username: "admin", password: "1111"}를 통해 AccessToken과 RefreshToken을 발급할 수 있다.

토큰 재발급

  • 토큰 재발급
    • 목적: AccessToken이 만료되었을 때 RefreshToekn을 가지고 새로운 AccessToken, RefreshToken을 발급받기 위해 사용된다.
    • 특징:
      • RefreshToken을 전달하여 신규 AccessToken, RefreshToken 발급
  • 발급 절차:
    • /security/jwt/refresh-token 통하여 위에AccessTokenFilter에서 생성한 RefreshToekn을 Request Hearder 에
      "Authorization": "Bearer YKDuD282j39s8" 예시로 Refresh 요청시 AccessToken과 RefreshToken 재발급이 가능하다.

API 인증

  • 인증 매커니즘

    • 기본적인 인증 매커니즘은 Spring Security의 인증 매커니즘을 그대로 사용하며, 아래와 같은 흐름으로 이루어진다.

      1. 인증 요청
        • 전달받은 AccessToken을 JwtFilter을 통해 검증하고, 유효한 토큰인 경우 UsernamePasswordAuthenticationToken을 생성한다.
      1. AuthenticationManager 위임
        • AuthenticationManager에 AuthenticationToken을 전달하여 인증을 위임한다.
      1. Authentication 정보 획득
        • AuthenticationManager에 등록된 AuthenticationProvider를 통해 Authentication 정보를 획득한다.
      1. RDB를 통한 인증 정보 획득
        • RDB를 통해 사용자 아이디를 기반으로 Authentication 정보를 획득하고, 사용자가 가진 권한 및 사용자가 속한 그룹의 권한 정보를 획득한다.
      1. 사용자 상태 확인 및 인증 수행
        • 사용자의 기본적인 상태(계정 잠김, 비활성화, 만료 등)를 확인하고, 정상적인 경우 패스워드를 검사하여 인증을 수행한다. 그 후, 비밀번호 상태(비밀번호 만료 등)를 확인한다.
      1. 인증 성공 후 처리
        • 인증이 성공하면, 원래 요청한 페이지로 redirect 된다.
  • 인증 절차
    • 발급된 AccessToken으로 Request Hearder 에 예제) "Authorization": "Bearer YKDuD282j39s8" 로 API 호출시 인증이 가능하다.

설정

  • 설정방법

    • 아래와 같이 파일내 설정을 해준다.

    • pom.xml

          <dependency>
              <groupId>net.lotte.chamomile.module</groupId>
              <artifactId>chamomile-security-jwt</artifactId>
          </dependency>
      • Autoconfiguration 설정에 의해 자동으로 Bean에 등록 된다.
      • 모든 모듈 구성은 해당 Bean에 의해 자동으로 구성된다.
      • 필요에 따라 수정이 필요한 부분은 별도의 Bean을 작성하여 사용자 정의할 수 있다.
    • application.yml

           chmm:  
              security:  
                  loginProcessingUrl: /security/jwt/authenticate  # AeccessToken,RefreshToken 발급
                  refreshProcessingUrl: /security/jwt/refresh-token  # 토큰재발급
                  defaultPasswordEncoder: sha256  # 패스워드 인코더 
                  passwordEncoderList: sha256,bcrypt  
                  rsaPassword:  # 패스워드 RSA 복호화
                      use : false  
                      # true: RSA 복호화 사용
                      # false : 일반 평문 사용(RSA 사용X)
                      privateKey :  
                  ignorePatterns:  ## Security 제외할 URI
                      - /chmm/user/update-password  
                      - /swagger-ui/**
                      - /api-docs/**
                      - /swagger-resources/**
                      - /v3/api-docs/**
                  autoconfig:  
                      use: true  
                      # true: autoconfig 설정에 의해 chamomile-security 모듈 자동등록
                      # false : 사용자단에서 별도의 SecurityConfiguration 구성 후 진행 가능
              jwt:  
                  secret: 0PtD9jRs2Q7Cgw38E8CNSBfxSf/ib/mAElN05fhAUU0FXsB3S8F3rfaaCSHy+NWQZkhDbs1SJm+cjdKQX4eHGA==  
                  access-expired-time: 18000000 #30분  
                  refresh-expired-time: 86400000 #24시간
              cache:  
                  instance: none #none/redis/hazelcast
                  # refresh 토큰저장소 none:DB, redis, hazelcast
      • 여기까지 설정 내용을 토대로 전체적인 로그인(AccesToken, RefreshToken), 토큰 재발급, API 인증이 가능하다.
      • 토큰 재발급을 위한 저장소는 기본은 DB이며 cache.instance 속성을 통행 redis와 hazelcast로 변경 할 수 있다.
      • 아래 내용에서 프로젝트 내에서 해당 클래스들을 직접 Bean으로 구성하여 커스터마이징할 수 있다.

커스터마이징

  • 토큰발급(로그인요청) 커스텀 예제

    • 토큰발급은 프로젝트 요구 사항에 맞게 수정이 가능하다.

    • CustomAccessTokenConfig.java

      • 프로젝트 내에 특정 패키지에 아래 CustomAccessTokenConfig.java를 생성해준다.
        @Configuration  
        public class CustomAccessTokenConfig {  
        @Bean
        @Primary
        public AccessTokenFilter accessFilter(AuthenticationManager authManager, JwtAuthentication jwtAuthentication, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {  
            AccessTokenFilter accessTokenFilter = new AccessTokenFilter(authManager, jwtAuthentication);  
            // 로그인 URL 설정  
            accessTokenFilter.setFilterProcessesUrl("/security/jwt/authenticate");  
            // 인증 성공 핸들러  
            accessTokenFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);  
            // 인증 실패 핸들러  
            accessTokenFilter.setAuthenticationFailureHandler(authenticationFailureHandler);  
            // BeanFactory에 의해 모든 property가 설정되고 난 뒤 실행  
            accessTokenFilter.afterPropertiesSet();  
            return accessTokenFilter;  
        }  
        }
      • `CustomAccessTokenConfig` 클래스는 Spring Security 필터 체인에 사용자 정의 인증 필터를 등록한다.
      • `AccessTokenFilter`는 실제 토큰을 생성하며, 자세한 설명은 아래의 AccessTokenFilter 섹션에서 진행한다.
      • 로그인 URL 설정은 .setFilterProcessesUrl("/security/jwt/authenticate")을 호출하여, 인증 요청이 해당 URL로 전송되도록 설정한다.
      • 인증 성공 및 실패 핸들러: 인증 성공시 `.setAuthenticationSuccessHandler(authenticationSuccessHandler)`를 호출하며 , 인증 실패 시 `.setAuthenticationFailureHandler(authenticationFailureHandler)`를 호출하여 해당 핸들러를 필터에 연결한다.
    • AccessTokenFilter.java

      • AccessTokenFilter는 사용자 계정 정보 확인 후 실제 AccessToken 및 RefreshToken을 생성한다.
      • 비밀번호 , 계정 유효성 검사에 대한 로직을 수정 할 수 있다.
      • 프로젝트 내에 특정 패키지에 아래 AccessTokenFilter.java를 생성해준다.

        @Configuration  
        public class AccessTokenFilter  extends UsernamePasswordAuthenticationFilter implements AccessTokenInterface {  
            @Autowired  
            private JdbcUserDetailsService jdbcUserDetailsService;  
            @Autowired  
            private PasswordDecoder passwordDecoder;  
            private final JwtAuthentication jwtAuthentication;  
        
        public AccessTokenFilter(AuthenticationManager authenticationManager, JwtAuthentication jwtAuthentication) {  
            super.setAuthenticationManager(authenticationManager);  
            this.jwtAuthentication = jwtAuthentication;  
        }  
        
        @Override  
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {  
        
            JwtRequest loginRequest;  
            DefaultUser userDetails;  
            Map token;  
        
            try {  
                    loginRequest = new ObjectMapper().readValue(request.getInputStream(), JwtRequest.class);  
                    LoggingUtils.userAccessLogging(loginRequest.getUsername(), UserAccessActionType.LOGIN_ATTEMPT);  
        
                    userDetails = (DefaultUser) jdbcUserDetailsService.loadUserByUsername(loginRequest.getUsername());  
        
                    String decryptPassword = passwordDecoder.decrypt(loginRequest.getPassword());  
                    // 비밀번호 확인  
                    jwtAuthentication.checkCredentials(decryptPassword, userDetails);  
                    // 계정 상태 검사 (만료, 잠김 등의 상태)  
                    jwtAuthentication.checkAccountStatus(userDetails);  
                    // JWT 토큰 생성  
                    token = jwtAuthentication.generateAndStoreTokens(userDetails);  
            } catch (ChamomileException ex) {  
                throw new AuthenticationServiceException(ex.getMessage(), new ChamomileException(((ChamomileException) ex).getFrameworkCode(), ex.getMessage()));  
            } catch (UsernameNotFoundException ex) {  
                throw new AuthenticationServiceException(ex.getMessage(), new ChamomileException(ChamomileExceptionCode.AuthenticationFailed, "authentication.fail.login"));  
            } catch (Exception ex) {  
                throw new AuthenticationServiceException(ex.getMessage());  
            }  
            // 요청 속성에 토큰 저장  
            request.setAttribute("jwtToken", token);  
            //계정 유효성 체크  
            return new JwtAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());  
        }  
        }
      • AccessTokenFilter 클래스는 UsernamePasswordAuthenticationFilter를 확장하여 사용자 이름과 비밀번호를 기반으로 인증을 시도하고, JWT 토큰을 생성하는 역할을 한다.
      • jdbcUserDetailsService.loadUserByUsername를 사용하여 데이터베이스로부터 해당 사용자명을 가진 사용자의 정보를 조회한다. 이 때 반환 되는 DefaultUser 객체는 사용자의 상세 정보를 담고 있다.
        • 사용자 정보 조회, 권한 정보 조회, 그룹 권한 정보 조회 등에 데이터 조회에 대한 쿼리 수정이 필요 할 경우 setUsersByUsernameQuery(), setAuthoritiesByUsernameQuery, setGroupAuthoritiesByUsernameQuery 메서드를 통하여 수정이 가능하다.
      • 비밀번호 검증 로직은 jwtAuthentication.checkCredentials 메서드를 통해 수행된다.
      • jwtAuthentication.checkAccountStatus사용자의 계정이 활성 상태인지 확인한다. 계정이 만료되었거나 잠겨 있는지 등의 상태를 검사하여, 사용이 가능한 상태인지 확인한다.
      • jwtAuthentication.generateAndStoreTokens 사용자의 상세정보를 기반으로 JWT 토큰을 생성한다.
    • LoginSuccessHandler.java

      • SampleLoginSuccessHandler는 AccessTokenFilter 에서 정상적인 토큰 발급 후 후 처리 역활을 한다.
      • 프로젝트 내에 특정 패키지에 아래 SampleLoginSuccessHandler는.java를 생성해준다.

        @Configuration  
        public class SampleLoginSuccessHandler implements AuthenticationSuccessHandler {  
            @Autowired  
            private JdbcLoginService jdbcLoginService;  
        @Override  
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,  
                Authentication authentication) throws IOException, ServletException {  
        
            try {  
                    Map token = (Map) request.getAttribute("jwtToken");  
                    jdbcLoginService.resetLockCnt(authentication.getName());  
                    // ObjectMapper를 사용하여 토큰을 JSON 문자열로 변환  
                    ObjectMapper objectMapper = new ObjectMapper();  
                    String tokenJson = objectMapper.writeValueAsString(new ChamomileResponse<>(token));  
                    LoggingUtils.userAccessLogging(authentication.getName(), UserAccessActionType.LOGIN_SUCCESS);  
        
                    // 응답에 JSON 형태로 토큰 추가  
                    response.setContentType("application/json;charset=UTF-8");  
                    response.setStatus(HttpServletResponse.SC_OK);  
        
                    // 응답 본문에 토큰 작성  
                    PrintWriter out = response.getWriter();  
                    out.print(tokenJson);  
                    out.flush();  
            } catch (Exception ex) {  
                  throw new ChamomileException(ChamomileExceptionCode.USER_AUTHENTICATION, ex.getMessage());  
            }  
        }  
        }
      • AccessTokenFilter.java 에서 성공적인 토큰 발급시 AuthenticationSuccessHandler 를 구현한 SuccessHandler를 통해 값을 리턴한다.
      • 성공시 필요한 기능을 커스텀하여 제공 할 수 있다.
    • LoginFailureHandler.java

      • SampleLoginFailureHandler는 AccessTokenFilter 에서 토큰 발급 실패시 후 처리 역활을 한다.
      • 프로젝트 내에 특정 패키지에 아래SampleLoginFailureHandler.java를 생성해준다.

        @Configuration  
        public class SampleLoginFailureHandler implements AuthenticationFailureHandler {  
            @Autowired  
            private JdbcLoginService jdbcLoginService;  
        @Override  
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,  
                AuthenticationException exception) throws IOException, ServletException {  
                try {  
                        String userID = request.getParameter("username");  
                        LoggingUtils.userAccessLogging(userID, UserAccessActionType.LOGIN_FAIL);  
                        ChamomileCode chamomileCode = null;  
                        Throwable cause = exception.getCause();  
                        if (cause instanceof ChamomileException) {  
                            chamomileCode = ((ChamomileException) cause).getFrameworkCode();  
                        }  
                        jdbcLoginService.lockProcessAccount(userID, exception);  
        
                        // 조건에 따른 코드 선택 및 메시지 설정  
                        int errorCode = chamomileCode == null ? chamomileCode.getCode() : ChamomileExceptionCode.USER_AUTHENTICATION.getCode();  
                        String errorMessage = chamomileCode == null ? chamomileCode.toString() : exception.getMessage();  
                        ChamomileResponse<Object> chamomileResponse = new ChamomileResponse<>(errorCode, errorMessage, null);  
        
                        // 응답 JSON 변환 및 설정  
                        ObjectMapper objectMapper = new ObjectMapper();  
                        String tokenJson = objectMapper.writeValueAsString(chamomileResponse);  
        
                        response.setContentType("application/json;charset=UTF-8");  
                        response.setCharacterEncoding("UTF-8");  
                        PrintWriter out = response.getWriter();  
                        out.print(tokenJson);  
                        out.flush();  
                } catch (Exception ex) {  
                    throw new ChamomileException(ChamomileExceptionCode.USER_AUTHENTICATION, ex.getMessage());  
                }  
            }  
        }
      • AccessTokenFilter.java 내 토큰 발급 실패시 AuthenticationFailureHandler 를 구현한 FailureHandler를 통해 값을 리턴한다.
  • 토큰 재발급 커스텀 예제

    • 토큰 재발급의 경우 프로젝트 상황에 맞게 수정이 가능하다.

    • CustomRefreshTokenConfig.java

      • 프로젝트 내에 특정 패키지에 아래 CustomAccessTokenConfig.java를 생성해준다.
        @Configuration  
        public class CustomRefreshTokenConfig {  
        @Autowired
        private ChamomileSecurityProperties securityProperties;
        @Bean  
        @Primary
        public RefreshTokenFilter refreshTokenFilter(AuthenticationManager authManager, JwtAuthentication jwtAuthentication, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {  
            RefreshTokenFilter refreshTokenFilter = new RefreshTokenFilter(authManager, jwtAuthentication);  
            // 필터 URL 설정  
            refreshTokenFilter.setFilterProcessesUrl(securityProperties.getRefreshProcessingUrl());  
            // 인증 성공 핸들러  
            refreshTokenFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);  
            // 인증 실패 핸들러  
            refreshTokenFilter.setAuthenticationFailureHandler(authenticationFailureHandler);  
            // BeanFactory에 의해 모든 property가 설정되고 난 뒤 실행  
            refreshTokenFilter.afterPropertiesSet();  
            return refreshTokenFilter;  
        }
        }
      • CustomRefreshTokenConfig 클래스는 Spring Security 필터 체인에 사용자 정의 인증 필터를 등록하는 역할을 한다.
      • RefreshTokenFilter는 실제 토큰을 생성하는 필터로 자세한 설명은 아래(RefreshTokenFilter)설명 에서 진행한다.
      • 토큰 재발급 URL 설정: .setFilterProcessesUrl("/security/jwt/refresh-token")을 호출하여, 인증 요청이 이 URL로 보내지도록 설정한다.
      • 토큰 재발급 성공 및 실패 핸들러: 인증 성공시 .setAuthenticationSuccessHandler(authenticationSuccessHandler)를 호출하며 , 인증 실패 시 .setAuthenticationFailureHandler(authenticationFailureHandler)를 호출하여 해당 핸들러를 필터에 연결한다.
    • RefreshTokenFilter.java

      • RefreshTokenFilter은 Refresh 토큰 검증과 사용자 계정 정보 확인 후 실제 AccessToken 및 RefreshToken을 재발급 해준다.
      • 프로젝트 내에 특정 패키지에 아래 RefreshTokenFilter.java를 생성해준다.

        @Configuration  
        public class RefreshTokenFilter extends UsernamePasswordAuthenticationFilter implements RefreshTokenInterface{  
            @Autowired  
            private JdbcUserDetailsService jdbcUserDetailsService;  
            @Autowired  
            private JwtTokenUtils jwtTokenUtils;  
            private final JwtAuthentication jwtAuthentication;  
        
        public RefreshTokenFilter(AuthenticationManager authenticationManager, JwtAuthentication jwtAuthentication) {  
            super.setAuthenticationManager(authenticationManager);  
            this.jwtAuthentication = jwtAuthentication;  
        }  
        
        @Override  
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {  
        
            String refreshToken;  
            String userName;  
            DefaultUser userDetails;  
            // refreshToken 에서 Subject 반환(userId)  
            try {  
                    // Header에서 토큰 파싱  
                    refreshToken = jwtTokenUtils.resolveToken(request);  
                    userName = jwtTokenUtils.extractUsername(refreshToken);  
                    // 리프레시 토큰 유효성 검사  
                    jwtAuthentication.validateRefreshToken(userName, refreshToken);  
                    // 사용자 조회  
                    userDetails = (DefaultUser) jdbcUserDetailsService.loadUserByUsername(userName);  
                    // 계정 상태 검사 (만료, 잠김 등의 상태)  
                    jwtAuthentication.checkAccountStatus(userDetails);  
                    // JWT 토큰 생성  
                    Map<String, String> token = jwtAuthentication.generateAndStoreTokens(userDetails);  
                    // 요청 속성에 토큰 저장  
                    request.setAttribute("jwtToken", token);  
                    // 계정 유효성 체크  
            } catch (ChamomileException ex) {  
                throw new AuthenticationServiceException(ex.getMessage(), new ChamomileException(((ChamomileException) ex).getFrameworkCode(), ex.getMessage()));  
            } catch (Exception ex) {  
                throw new AuthenticationServiceException(ex.getMessage());  
            }  
            return new JwtAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());  
        }  
        }
      • RefreshTokenFilter 클래스는 UsernamePasswordAuthenticationFilter를 확장하여 RefreshToken 검증과 사용자 이름과 비밀번호를 기반으로 인증을 시도하고, JWT 토큰을 재발급하는 역할을 한다.
      • jwtTokenUtils.resolveToken, jwtTokenUtils.extractUsername 를 사용하여 Request Header에서 RefreshToken을 파싱한다.
      • jwtAuthentication.validateRefreshToke를 사용하여 RefreshToekn에 유효성을 검사한다.
      • jdbcUserDetailsService.loadUserByUsername를 사용하여 데이터베이스로부터 해당 사용자명을 가진 사용자의 정보를 조회한다. 이 때 반환 되는 DefaultUser 객체는 사용자의 상세 정보를 담고 있다.
      • 비밀번호 검증 로직은 jwtAuthentication.checkCredentials 메소드를 통해 수행된다.
      • jwtAuthentication.checkAccountStatus사용자의 계정이 활성 상태인지 확인한다. 계정이 만료되었거나 잠겨 있는지 등의 상태를 검사하여, 사용이 가능한 상태인지 확인한다.
      • jwtAuthentication.generateAndStoreTokens 사용자의 상세정보를 기반으로 JWT 토큰을 생성한다.
    • API 인증 커스텀 예제

    • API 인증의 경우 프로젝트 상황에 맞게 수정이 가능하다.

    • JwtAuthenticationProvider.java

      • 프로젝트 내에 특정 패키지에 아래 JwtAuthenticationProvider.java를 생성해준다.

        @Configuration  
        public class JwtAuthenticationProvider implements AuthenticationProvider  {  
        
            @Autowired  
            private JdbcUserDetailsService jdbcUserDetailsService;  
            @Autowired  
            private PasswordEncoder passwordEncoder;  
            @Autowired  
            private JwtTokenUtils tokenUtils;  
            @Autowired  
            private  JwtAuthentication jwtAuthentication;
        
        @Override  
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {  
            try {  
                String jwtToken = (String) authentication.getCredentials();  
        
                //refreshToken을 통한 API 호출 차단  
                if ("refresh".equals(tokenUtils.extractClaimName(jwtToken))) {  
                    throw new ChamomileException(ChamomileExceptionCode.USER_AUTHENTICATION, "The refresh token cannot be used");  
                }  
                String userName = tokenUtils.extractUsername(jwtToken);  
                //입력받은 AccessToken 내 userName으로 사용자 정보(UserDetails)를 조회하여 반환한다. (사용자정보, 사용자권한 사용자그룹권한)  
                DefaultUser userDetails = (DefaultUser) jdbcUserDetailsService.loadUserByUsername(userName);  
                //계정 유효성 체크  
                jwtAuthentication.checkAccountStatus(userDetails);  
                return new JwtAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());  
        
            } catch (ChamomileException ex) {  
                throw new AuthenticationServiceException(ex.getMessage(), new ChamomileException(((ChamomileException) ex).getFrameworkCode(), ex.getMessage()));  
            } catch (Exception ex) {  
                throw new AuthenticationServiceException(ex.getMessage());  
            }  
        }
        
        @Override  
        public boolean supports(Class<?> authentication) {  
            return JwtAuthenticationToken.class.isAssignableFrom(authentication);  
        }  
        }
      • tokenUtils.extractUsername AccessToken 을 파싱하여 userName을 반환한다.
      • checkAccountStatus 사용자에 대한 유효성 검사를 한다.
  • ChamomileSecurityJwtConfiguration 커스터마이징

    • 캐모마일 JWT 시큐리티 설정에 대한 전반적인 수정이 필요한 경우 아래 properties내 설정 후 전체적인 커스텀 및 사용자가 작성한 Security 적용이 가능하다.

    • 단 캐모마일 JWT 시큐리티에 대한 커스텀이 아닌 새로운 SecurityConfiguration 구성시 pom.xml 내 chamomile-security-jwt 의존성을 제거 후 진행한다.

    • 설정방법

          chmm:
              # custom 
              autoconfig:
                  use: false  
                  # true: autoconfig 설정에 의해 chamomile-security 모듈 자동등록
                  # false : 사용자단에서 별도의 SecurityConfiguration 구성 후 진행 가능
    • 아래 CustomsecurityJwtConfiguration.java 를 예시로 설정시 전체적인 커스텀이 가능하다.

    • CustomsecurityJwtConfiguration.java 전체 소스는 캐모마일 담당자를 통해 요청시 제공한다.

    • CustomsecurityJwtConfiguration.java

      • 프로젝트 내에 특정 패키지에 아래 CustomsecurityJwtConfiguration.java을 생성해준다.

        @Configuration  
        @EnableWebSecurity  
        @ConditionalOnProperty(  
        name = {"chmm.security.autoconfig.use"},  
        havingValue = "false"  
        )  
        @ConditionalOnClass(name = "net.lotte.chamomile.module.security.jwt.filter.JwtFilter")  
        public class ChamomileSecurityJwtConfiguration  {  
        private final ChamomileSecurityProperties securityProperties;  
        private final ChamomileSecurityCorsProperties chamomileSecurityCorsProperties;  
        private final DataSource dataSource;  
        
        public ChamomileSecurityJwtConfiguration(ChamomileSecurityProperties securityProperties, ChamomileSecurityCorsProperties chamomileSecurityCorsProperties, DataSource dataSource) {  
            this.chamomileSecurityCorsProperties = chamomileSecurityCorsProperties;  
            this.dataSource = dataSource;  
            this.securityProperties = securityProperties;  
        }  
        /**  
         * 인증 요청에 대한 처리 메서드  
         * JdbcUserDetailsService PasswordEncoder가 자동으로 설정 (provider 사용안할시)  
         * 복수 공급자 사용시 provider 수정 사용하여 이용 가능  
         * @param authenticationConfiguration  
         * @return  
         * @throws Exception  
         */  
        @Bean  
        public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {  
            return authenticationConfiguration.getAuthenticationManager();  
        }
        
        /** 이하 내용 생략 **/
        }

CORS

  • CORS는 웹 페이지가 다른 도메인의 리소스에 접근할 수 있도록 허용하는 메커니즘 이다.
  • application.yml chmm 하위에 아래와 같이 추가해 준다.
    chmm:
        cors:
            configurations:
                - pattern: "/**" # 모든 경로에 대해 CORS 설정을 적용
                  allowed-origins: #  접근을 허용할 출처(origin)를 지정
                      - "http://localhost:8080" # 로컬호스트의 8080 포트에 대한 접근을 허용
                      - "http://localhost:23636" # 로컬호스트의 23636 포트에 대한 접근을 허용
                  allowed-methods: # 허용할 HTTP 메소드를 지정
                      - "GET" 
                      - "POST" 
                  allowed-headers: # 허용할 HTTP 헤더를 지정합니다.
                      - "Authorization" # Authorization 헤더를 허용합니다 (예: 토큰을 사용한 인증에 사용됩니다).
                      - "Content-Type" # Content-Type 헤더를 허용합니다 (예: 요청 본문의 미디어 타입을 지정합니다).
                  allow-credentials: false # 쿠키나 인증 관련 헤더를 사용하여 사용자 인증 정보를 포함시키지 않도록 합니다.
                  max-age: 3600 # 브라우저가 CORS 관련 설정을 캐시할 시간을 초 단위로 지정합니다 (여기서는 3600초, 즉 1시간입니다).
다음 시큐리티(세션)