spring security chatper2
스프링시큐리티인액션2 챕터2 정리부분입니다.
httpsecurity를 통해서 인증 필터링 거는 방법입니다.
책에 보면
@Override
protected void configure(HttpSecurity http) throws Exception {
위와 같은 코드가 나오는데요.
이 부분은 크게 2가지 방법으로 구현됩니다.
책에서 나온 방법은
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
websecurityconfigureadapter를 상속받아서 사용을 했습니다.
그래서
아래와 같이 configure를 override해서 사용이 가능합니다.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().disable()
.authorizeRequests()
.antMatchers("/test/**").permitAll()
.anyRequest().authenticated()
위의 명령어를 통해서 /test/**는 무조건 인증없이 통과시키고
나머지는 모두 인증을 받아야지 리소스에 접근이 가능하빈다.
antMatchers는 책에서 따로 나오지 않았습니다.
그리고 두번째 방법으로는
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
상속없이 하는 방법입니다.
참고로 이 방법은 자바 11버전 , 스프링부트 2.7 그리고 dsl로 셋팅된 프로젝트입니다.
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.4'
id 'io.spring.dependency-management' version '1.0.14.RELEASE'
}
group 'org.example'
version '1.0-SNAPSHOT'
sourceCompatibility = '11'
targetCompatibility = '11'
차이점이 위에서 사용했던 security방법은 override하는 방식으로 되어 있는데
지금은 bean 을 등록해서 사용하는 방식입니다.
빈 어노테이션을 사용하는 방법이 가장 최신 방법이고 그 이외의 http에서 authorizeRequests방법은 비슷합니다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.headers().frameOptions().disable()
.and()
.authorizeRequests()
그리고 사용자 등록을 할 때 패스워드 암호화하는 방식이 나왔는데
암호화 방식은 크게 2가지가 있습니다.
정말 간단하게 설명하자면
암호화 방식은 디코딩이 가능한 방식과 불가능한 방식으로 나뉩니다.
만약 db가 해킹이 되었을 경우
디코딩이 가능하다면 사용자 암호가 그대로 노출될 가능성이 있습니다.
그래서 암호는 디코딩 불가능한 방식.
주민번호나 사용자 이름같은 경우에는 디코딩이 가능한 방식으로 하는 것이 좋습니다.
물론 주민번호도 전체를 디코딩 가능하도록 설정하는게 아니라 생년월일 정도로만 나눠서 디코딩 가능하도록 설정하는게 좋습니다.
아래는 실제로 회원가입을 하는 소스입니다.
이때 보는 것처럼 passwordencoder를 통해서 암호화를 합니다.
public Users signUp(UserRequest request){
Users user = Users.builder()
.userId(request.getUserId().trim())
.name(request.getName().trim())
.password(passwordEncoder(request.getPassword().trim()))
.regNo(request.getRegNo().trim())
.build();
return userRepository.saveAndFlush(user);
}
참고로 이 암호화 방식은
private String passwordEncoder(String password) { return bCryptPasswordEncoder.encode(password); }
private final BCryptPasswordEncoder bCryptPasswordEncoder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
스프링시큐리티에서 제공하는 암호화방식입니다.
예를 들어 암호가 1234일 경우에
위의 암호화 방식을 사용하면
1234 -> efefe11@$$이런식으로 변경이 됩니다.
근데 다른 사용자 또한 암호를 1234를 사용했을 경우에는
1234 -> eefee11@
이런식으로 똑같이 암호화 되는 것이 아닌 다른 방식으로 암호화가 됩니다.
이럴 경우 장점이 하나의 암호가 털리더라도 디코딩 하는 것이 불가능합니다.
참고로 이 방식을 사용하기 위해서는
securityconfugration에 아래와 같이 bean으로 등록을 해줘야 합니다.
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
비밀번호 암호화는 디코딩이 불가능하도록 설정하고 만약 주민번호 같은 컬럼을 디코딩 가능하도록 처리하려면 어떻게 해야 할까요?
실제로 구현하기 전에 생각해 봐야 할 것이
데이터베이스에서는 암호화된 상태로 들어가야하고 사용자한테 보여줄때는 디코딩해서 원래 값을 보여줘야 합니다.
매번 그리고 주민등록번호를 추가될 때마다 이런 로직을 추가해야 한다면 아주 불편하겠죠.
그렇기 때문에
아래와 같이 convert 어노테이션을 사용하면 됩니다.
@Column
@Convert(converter = CryptoStringConverter.class)
private String regNo;//주민등록번호
스프링부트의 사상 자체가 대부분의 모든 것들을 어노테이션을 통해서 사용이 가능하도록 처리했습니다.
위에서 봤던 것처럼 security 옵션도 상속이 아닌 어노테이션을 받아서 사용하는 것처럼 말이죠.
컨터버 어노테이션을 외부로 끌어내고
@Converter
public class CryptoStringConverter implements AttributeConverter<String, String> {
@Override
public String convertToDatabaseColumn(String attribute) {
if (attribute == null) return null;
return Seed.encrypt(attribute);
}
@Override
public String convertToEntityAttribute(String dbData) {
if (dbData == null) return null;
return Seed.decrypt(dbData);
}
}
위와 같이 클래스로 빼서 사용하면 아주 편리해집니다.
이러면 데이터베이스에서는 암호화된 상태로 보여주고 화면에서는 로우값을 그대로 보여줄 수 있습니다.
2장 자체는 지금까지 많이 사용했던 기능들이라서
최신 트렌드를 반영해서 추가 했습니다.