JWT 시그니처에는 헤더와 페이로드를 합친 문자열을 서명한 값이 들어 있다.
서명은 헤더의 알고리즘과 secret key 를 이용해 생성. Base64 URL - safe 로 인코딩한다.
secret key 를 포함해서 암호화가 되어있다.
☘️ 사전 작업
1. <SecurityConfiguration> 1 : 보안 구성 클래스 @Configuration
- SecurityFilterChain : 최소한의 보안 구성.
- passWordEncoder. : passwordEncoder Bean 객체 생성.
- corsConfigurationSource : Cors 정책 적용.
- setAllowedOrigins() : 모든 출처(Origin) 에 대해 HTTP 통신을 허용하도록 함.
- setAlloweddMethods () : 파라미터로 지정한 HTTP Method 에 대한 HTTP 통신 허용
- UrlBasedCorsConfigurationSource : 구현 클래스.
2. 회원 가입 로직 수정
- <MemberDto> : password 추가.
- <Member> : 엔티티에 password, roles 추가. @ElementCollection (fetch = FetchType.EAGER)
- <MemberService> : createMember 에서
- password 단방향 암호화
- DB에 user role 저장 : email 을 받아서 Role 저장. authorityUtils 클래스 필요.
- authorityUtils
- Role 기반의 권한 생성 List<GrantedAuthority>, DB 를 위한 List<String>.
- 회원 가입 시 Email 을 받아 List<String> Role 을 만듦. >> MemberService 에서 사용
- 만든 List<String> 을 Spring Security 를 위한 List<GrantedAuthrity> 생성. >>MemberDetailsService 에서 사용
- authorityUtils
☘️ 로그인 인증 구현
1. <MemberDetailsService> : DB에서 사용자의 크리덴셜을 조회 후 AuthenticationManager 에게 전달.
- UserDetailsService 인터페이스를 구현, loadUserByUsername 오버라이딩.
- <MemberDetails> 내부 클래스 : UserDetails 구현, Member 상속
- MembeDetails 생성자로 DB의 member 요소 set 으로 받음.
- getAuthorities 메서드로 권한 생성. DB의 roles 을 Authories 로 반환.
- getUsername 메서드로 DB의 Email을 username 으로 반환.
2. <LoginDto> : 로그인 인증 정보 역직렬화.
- 역직렬화: Json 형태를 객체로 반환. security filter에서 사용 목적
- 클라이언트의 Username, password 정보만 담음.
3. <JwtTokenizer> : 로그인 인증에 성공하면, JWT 생성 밑 발급, 요청이 들어올 때마다 전달된 JWT 검증.
- Jws : jwt 의 signature
- Claims : Payload 에 있는 토큰에서 사용할 정보들의 조각. ⭐️ 중요한 credential 정보는 담지 않는다.
- iss : 토큰 발급자(issuer) – Public Claims
- sub : 토큰 제목(subject) – Public Claims
- iat : 토큰 발급 시간(issued at) – Public Claims
- exp : 토큰 만료 시간(expiration) – Public Claims
- roles : 권한 – Private Cliams
- JWT 생성 및 검증 시 사용되는 Secret Key, Access Token 만료 시간 정보, Refresh Token 만료 시간 정보.
- encodeBase64SecretKey() : secretKey 암호화.
- getKeyFromBase64EncodeKey() : base64EncodedSecretKey 복호화 >> 해시함수로 암호화.
- generateAccessToken (): claims 를 포함한, accesstoken.
- generateRefreshToken () : RefreshToken 생성.
- getClaims (): jwt 에서 Jws<Claims> 를 만들어서 반환. 나중에 검증할 때 사용.
- verifySignature () : signature 검증용.
- getTokenExpiration() : 만료 시간 반환.
4. <JwtAuthenticationFilter> : UsernamePasswordAuthenticationFilter 상속
- UsernamePasswordAuthenticationFiler : Username/Password 기반의 인증 처리 위해 확장해서 구현 가능.
- AuthenticationManager : 의존성 주입. 로그인 인증 정보를 전달받아, 인증 여부 판단.
- JwtToenizer : 의존성 주입. 인증에 성공했으면 JWT 생성 및 발급.
- attemptAuthentication : 인증을 시도하는 로직 구현.
- ObjectMapper: json 형태의 Username, Password 를 LoginDto 클래스의 객체로 역직렬화.
- UsernamePasswordAuthenticationToken : 받은 Username, Password 로 생성해서, AutneticationManager 로 전달해서 인정 처리 위임.
- successfulAuthentication : AuthenticationManager내부에서 인증 성공되면 인증된 Authentication 객체 생성. Member 객체 할당
- delegateAccessToken(member) : Access Token 생성
- delegateRefreshToken(member) : Refresh Token 생성
- responseheader 에 Access Token 추가, Refresh Token 추가.
5. <SecurityConfiguration> 2 : 설정 업데이트
- <CustomFilerConfigurer> : JwtAuthenticationFilter 를 등록하는 역할, AbstractHttpconfigurer 상속.
- HttpSecurity 의 getShareObject() : AuthenticationManager 를 얻을 수 있음.
- JwtAuthenticationFilter 생성, AuthenticationMaager, JwtTokenizer DI 함.
- setFilterProcessesUrl() : URL 설정.
- addFilter() : Spring Security Filter Chain 추가.
- SecurityFilterChain 에 CustomFilterConfigurer 추가.
- AuthenticationSuccessHandler, AuthenticationFailureHandler, JwtVerificationFilter 구현 해야 함.
☘️ 로그인 성공, 실패에 따른 추가 처리
1. <MemberAuthenticationSuccessHandler> : AuthenticationSuccessHandler 를 구현.
- 로그인 인증에 성공했을 때 로그 기록.
2. <MemberAuthenticationFailureHandler> : AuthenticationFailureHandler 를 구현.
- 로그인 인증 실패 시 추가 작업.
- onAuthenticationFailure() 추상 메서드 : Response 의 status 가 401 임을 클라이언트에 알려줄 수 있어야 함.
- UNAUTHORIZED (401)
등록한 이메일 주소와 패스워드를 이용해 로그인 인증을 성공적으로 수행 >>> 인증 성공에 대한 정보가 담겨져 있는 JWT 전달 받음.
☘️ 자격 증명 및 검증 구현
- 클라이언트 측에서, 자격 증명이 필요한 리소스에 대한 request 시,
- request header 를 통해 전달받은 JWT 를 서버 측에서 검증.
1. <JwtVerificationFilter> : request 당 한번만 실행 하므로 OncePerRequestFilter
- claims : payload 에 담겨져 있음. Map의 key, value 형태로.
- Jws : s는 서명된(Signed) JWT, signature, ??????????
- verifyJws() : JWT 검증 하는데 사용되는 메서드.
- JWT 검증 위한 Secret Key 를 얻음.
- JWT 에서 Claims 파싱 :: 내부적으로 서명 검증에 성공했다는 의미.
- 이게 정상적으로 오면 서명 검증이 자연스럽게 성공했다는 뜻. verify() 매서드가 따로 있는 것이 아님.
- JwtTokenizer 의 getClaim() 이 Jws<Claims>를 반환을 하려며는 검증이 되어야 할 수 있음. ?????????
- setAuthenticationToContext() : Authentication 객체를 SecurityContext 에 저장.
- Username: JWT 에서 받은 Claims 에서 받음.
- List<GrantedAuthority> : JWT 의 Claims 를 기반으로 생성.
- Authentication 객체 : username, List<GrantedAuthority> 포함. >>> SecurityContext 에 저장.
- Context 에 저장된 Authentication 객체는 Spring Security 의 세션 정책에 따라 생성할 수도 아닐수도.
- shouldNotFilter() : 특정 조건에 부합하면 filter 동작 수행하지 않음.
- request 로 받은 Authorization header 값이 Null, Bearer 로 시작하지 않으면 filter 수행하지 않도록 함.
- JWT 가 포함되지 않았으면, 자격증명이 필요 없는 리소스라 판단. >> 다음 filter 로 건너뜀.
2. <SecurityConfiguration> 3 설정 업데이트
- .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS): 세션 stateless 애플리케이션 유지.
- 단일 요청에 대한 하나의 응답.
- 서버가 클라 상태를 보존 하지 않음.
- .apply(new CustomFilterConfigurer()) : <CustomFilterConfigurer> 에 JwtVerificationFilter 추가
- JwtAuthenticationFilter 뒤에 추가.
- 로그인 인증에 성공한 후, 발급 받은 JWT 가 request header(Authorization)에 포함되어 있을 때에만 동작.
- .authorizeHttpRequests: 접근 권한 설정 서버 측 리소스 역할(Role) 기반 권한 적용
- antMatchers(HttpMethod.POST ~ ) : 회원 가입. 모든 사용자 권한 부여.
- antMatchers(HttpMethod.PATCH ~ ) : 회원 정보 수정. USER 권한 부여.
- antMatchers(HttpMethod.GET "/*/members" ) : 모든 회원 정보 조회. ADMIN 권한 부여.
- antMatchers(HttpMethod.POST "/*/members/**" ) : 특정 회원 정보 조희. USER, ADMIN 권한 부여.
- antMatchers(HttpMethod.DELETE ~ ) : 회원 탈퇴. USER 권한 부여.
☘️ 예외 처리 (JwtVerificationFilter 수정)
- SignautureException : JWT에 대한 서명 검증 실패 시 throw 됨.
- ExpiredJwtException : JWT 만료 시 throw 됨.
'Spring > Security' 카테고리의 다른 글
@HttpServletRequest (0) | 2025.03.24 |
---|---|
[Spring] OAuth2 인증 용어 (1) | 2024.07.10 |