RememberMe 인증
- 사용자가 웹 사이트나 애플리케이션에 로그인할 때 자동으로 인증 정보를 기억하는 기능
- UsernamePasswordAuthenticationFilter와 함께 사용
- AbstractAuthenticationProcessingFilter 슈퍼 클래스에서 훅을 통해 구현
- 인증 성공 시 RememberMeServices.loginSuccess()를 통해 RememberMe 토큰을 생성하고 쿠키로 전달
- 인증 실패 시 RememberMeServices.loginFail()을 통해 쿠키를 지움
- LogoutFilter와 연계해서 로그아웃 시 쿠키를 지움
토큰 생성
- 기본적으로 암호화된 토큰으로 생성되며 브라우저에 쿠키를 보내고, 향후 세션에서 이 쿠키를 감지하여 자동 로그인이 이루어지는 방식으로 달성
→ 단방향으로 암호화가 되기 때문에 복호화가 불가하여 중요한 데이터가 노출되지 않음
(단, 탈취한 토큰으로 인증은 가능)
base(username + ":" + expirationTime + ":" + algorithmName + ":"
+ algorithmHex(username + ":" + expirationTime + ":" + password + ":" + key))
- username : UserDetailsService로 식별 가능한 사용자 이름
- password : 검색된 UserDetails에 일치하는 비밀번호
- expirationTime : remember-me 토큰이 만료되는 날짜와 시간(밀리초 표현)
- key : remember-me 토큰의 수정을 방지하기 위한 개인 키
- algorithmName : rememeber-me 토큰 서명을 생성하고 검증하는 데 사용(기본적으로 SHA-256 알고리즘 사용)
RememberMeServices 구현체
- TokenBasedRememberMeServices → 쿠키 기반 토큰의 보안을 위해 해싱 사용(메모리에 저장하는 메모리 방식)
- PersistentTokenBasedRememberMeServices → 생성된 토큰을 저장하기 위해 데이터베이스나 다른 영구 저장 매체 사용
- 두 구현 모두 사용자의 정보를 검색하기 위한 UserDetailsService 필요
rememberMe() API
- RememberMeConfigurer 설정 클래스를 통해 여러 API 설정 가능
- 내부적으로 RememberMeAuthenticationFilter 가 생성되어 자동 인증 처리 담당
http.rememberMe(httpSecurityRememberMeConfigurer -> httpSecurityRememberMeConfigurer
.alwaysRemember(true) // "기억하기(remember-me)" 매개변수가 설정되지 않았을 때에도 항상 기억하기 사용
.tokenValiditySeconds(3600) // 토큰이 유효한 시간(초 단위)을 지정 가능
.userDetailsService(userDetailService) // UserDetails 를 조회하기 위해 사용되는 UserDetailsService를 지정
.rememberMeParameter("remember") // 로그인 시 사용자를 기억하기 위해 사용되는 HTTP 매개변수, 기본값은 remember-me
.rememberMeCookieName("remember") // 기억하기(remember-me) 인증을 위한 토큰을 저장하는 쿠키 이름, 기본값은 remember-me
.key("security") // 기억하기(remember-me) 인증을 위해 생성된 토큰을 식별하는 키를 설정
)
IndexController 코드
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@GetMapping("/")
public String index(){
return "index";
}
@GetMapping("/loginPage")
public String login(){
return "loginPage";
}
}
SecurityConfig 코드
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests( auth -> auth.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.rememberMe(rememberMe -> rememberMe
// .alwaysRemember(true) // "기억하기" 매개변수가 설정되지 않았을 때에도 쿠키가 항상 생성되어야 함
.tokenValiditySeconds(3600) // 토큰이 유효한 시간(초 단위)
.userDetailsService(userDetailsService()) // UserDetails를 조회하기 위해 사용되는 UserDetailsService 지정
.rememberMeParameter("remember") // 로그인 시 사용자를 기억하기 위해 사용되는 HTTP 매개변수
.rememberMeCookieName("remember") // 기억하기 인증을 위한 토큰을 저장하는 쿠키 이름
.key("security")); // 기억하기 기능을 사용하기 위한 키
return http.build();
}
@Bean
public UserDetailsService userDetailsService(){
UserDetails user = User.withUsername("user").password("{noop}1111").roles("USER").build();
return new InMemoryUserDetailsManager(user);
}
}
테스트
- localhost:8080 접속하여 Remember me 체크 후 로그인
- F12 개발자 도구에서 remember 쿠키가 생성된 것 확인
- JSESSION ID 우 클릭 → Delete
- localhost:8080 재 접속
- → 쿠키가 없었다면 loginPage로 이동되었어야 함
- localhost:8080 Remember me 체크하지 않고 로그인
- F12 개발자 도구에 remember 쿠키 없는 것 확인
- JSESSIONID 삭제 후 재 접속
- loginPage로 리다이렉트
- RememberMe는 기억하기 위해 쿠키를 만듦
- JSESSIONID가 삭제 되더라도 쿠키만 남아있으면 인증을 거치지 않음(자동 로그인)
- 로그아웃 시 LogoutFilter와 연계하여 함께 삭제
'Language > Spring Security' 카테고리의 다른 글
익명 사용자 - anonymous() (0) | 2024.07.16 |
---|---|
기억하기 인증 필터 - RememberMeAuthenticationFilter (0) | 2024.07.16 |
기본 인증 필터 - BasicAuthenticationFilter (0) | 2024.07.16 |
기본 인증 - httpBasic() (0) | 2024.07.16 |
폼 인증 필터 - UsernamePasswordAuthenticationFilter (0) | 2024.07.15 |