🍃Spring Security Documentation
// 스프링 시큐리티
implementation 'org.springframework.boot:spring-boot-starter-security'
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// image 폴더를 login 없이 허용
.antMatchers("/images/**").permitAll()
// css 폴더를 login 없이 허용
.antMatchers("/css/**").permitAll()
// 어떤 요청이든 '인증'
.anyRequest().authenticated()
.and()
// 로그인 기능 허용
.formLogin()
.loginPage("/user/login")
.defaultSuccessUrl("/")
.failureUrl("/user/login?error")
.permitAll()
.and()
// 로그아웃 기능 허용
.logout()
.permitAll();
}
}
WebSecurityConfig (springboot 2.7이상)
package com.sparta.springsecurity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// CSRF 설정
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated();
// 로그인 사용
http.formLogin();
return http.build();
}
}
🍃 pring security - CSRF란?, http.csrf().disable() ?
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// CSRF 설정
http.csrf().disable();
http.authorizeHttpRequests().anyRequest().authenticated();
// 로그인 사용
http.formLogin();
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
// h2-console 사용
return (web) -> web.ignoring()
.requestMatchers(PathRequest.toH2Console())
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
.requestMatchers(PathRequest.toH2Console())
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
은
.antMatchers("/h2-console/").permitAll()
.antMatchers("/css/").permitAll()
.antMatchers("/js/").permitAll()
.antMatchers("/images/").permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
이 경로들을 한 번에 설정을 해줄 수 있는 방법으로
ignoring을 이용 하여
이러한 경로로 들어오는 것들은 인증처리하는 것을 무시하겠다는 의미
.antMatchers("/api/users/**")
특정 리소스에 대해서 권한을 설정한다.
.antMatchers("/api/users/**").permitAll()
antMachers 설정한 리소스의 접근을 인증절차 없이 허용한다는 의미
antMatchers("/admin/**").hasAnyRole("ADMIN")
리소스 admin으로 시작하는 모든 URL은 인증 후 ADMIN레벨의 권한을가진 사용자만 접근을 허용한다는 의미입니다.
anyRequest().authenticated()
모든 리소스를 의미하며 접근허용 리소스 및 인증후 특정 레벨의 권한을 가진 사용자만 접근가능한 리소스를 설정하고 그외 나머지 리소스들은 무조건 인증을 완료해야 접근이 가능하다는 의미입니다.
우리가 디폴트 Form Login을 사용한다고 했는데
// 로그인 사용
http.formLogin();
Security에서 제공하는 디폴트 Form Login을 사용을 하겠다라는 의미로 로그인 페이지와 기타 로그인 처리 및 성공 실패 처리를 사용하겠다는 의미
기본적으로 서버가 시작을 할 때마다 제공하는 디폴트 password가 존재한다.
그리고 username은 user로 고정이 되어 있다.
그래서 username의 user 그리고 패스워드에는 콘솔창에 나와 있는이 값을 사용하면
인증처리가 완료되고 Session ID가 제공이 된다.
url에 localhost:8080/login 요청을 하면 form Login 방식이기 때문에 지금 인증이 되지 않은 요청 이어서 기본 로그인 창이 반환이 된다.
그럼 여기서 제공을 한 패스워드를 복사해서 붙여넣고 user로 로그인 하면 우리가 넣어 놨던 index.html이 막히지 않고 인증이 되어서 나오는 걸 볼 수 있다.
그러면 세션이 잘 넘어왔는지 확인 ~
F12 - 쿠키저장소에 보면 세션이 넘어와 있다.
이 세션이 재로딩이 되도 동일한 값이 들어온다.
근데 만약 이 세션을 삭제를 한다면 -> 다시 로그인 창으로 들어온다.그리고 세션값도 바뀌었다.
세션값을 통해서 인증처리가 된다는 것을 확인 할 수 있다.
👍Spring Security는 기본적으로는 Session방식을 사용을 해서 인증 처리를 한다.
현재 로그인 창이 밋밋하여 우리가 만든 로그인 페이지를 사용
// Custom 로그인 페이지 사용
http.formLogin().loginPage("/api/user/login-page").permitAll();
이러한 폼로그인방식에서 인증이 되지 않는 요청을 로그인 페이지로 보낼 때 기존의 로그인페이지가 아니라
우리가 Custom한 로그인 페이지를 반환을하는 url로 요청이 된다. 그럼 permitAll()로 이 요청은 다 허가해 주겠다라는 의미
사용자가 따로 만든 로그인 페이지를 사용하려고 할때 설정한다.
loginPage("/api/user/login-page")
따로 설정하지 않으면 디폴트 URL이 “/login”이기 때문에 “/login”로 호출하면 스프링이 제공하는 기본 로그인페이지가 호출된다.
로그인 즉 인증 처리를 하는 URL을 설정합니다. “/login-process” 가 호출되면 인증처리를 수행하는 필터가 호출된다.
loginProcessingUrl("/login-process")
로그인 FORM에서 아이디와 비번을 입력하고 확인을 클릭하면 “/login-process” 를 호출 하게 되었들 때 인증처리하는 필터가 호출되어 아이디 비번을 받아와 인증처리가 수행되게 된다. 즉 UsernamePasswordAuthenticationFilter가 실행 되게 되는 것이다.
정상적으로 인증성공 했을 경우 이동하는 페이지를 설정한다.
defaultSuccessUrl("/main")
설정하지 않는경우 디폴트값은 “/”이다.
커스텀 핸들러를 생성하여 등록하면 인증성공 후 사용자가 추가한 로직을 수행하고 성공 페이지로 이동한다.
인증이 실패 했을 경우 이동하는 페이지를 설정한다.
failureUrl("/login-fail")
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig {
private final JwtUtil jwtUtil;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
// h2-console 사용
return (web) -> web.ignoring()
.requestMatchers(PathRequest.toH2Console())
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.httpBasic().disable() // rest api 이므로 기본 설정 미사용
.csrf().disable() // rest api 이므로 csrf 보안 미사용
.formLogin().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // jwt 사용하므로 세션 미사용
.and()
.authorizeHttpRequests()
.antMatchers("/api/users/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint())
.and()
.exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler())
.and()
.addFilterBefore(new JwtAuthFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
도움받고 갑니다. 감사합니다