자바/Spring

Spring Security 3.1.1 적용

끄적끄적 2023. 9. 16. 21:54
  • SecurityFilterChain : 기존에 2.x버전에서 WebSecurityConfigurerAdapter 상속받아 configure 재정의하던 방식에서 @Bean으로 생성하도록 변경되었다
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

		return http
			.csrf((csrf) -> csrf.disable())
			.authorizeHttpRequests(request -> request.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
				.requestMatchers(staticPath.toArray(new String[0])).permitAll()
				.requestMatchers("/", "/inventory/**",  "/account/**", "/api/**")
				.permitAll()
				.requestMatchers("/admin/**", "/report/**").hasAnyRole( AdminRole.MANAGER.name(), AdminRole.ADMIN.name())
				.requestMatchers("/manage/**").hasAnyRole(AdminRole.USER.name(), AdminRole.ADMIN.name())
				.anyRequest()
				.authenticated())
			.formLogin(Customizer.withDefaults())
			.build();
	}
  • PasswordEncoder : @Bean으로 생성해줘야 한다. 주로 BCryptPasswordEncoder 를 많이 사용한다.
    • BCryptPasswordEncoder 는 해쉬값이 동일한 것을 방지하기 위해, 해쉬처리의 반복과 솔트처리(원문에 임의의 문자열 붙이기)를 이용
    • strengh는 반복횟수에 영향을 주어 크게 줄 경우 해쉬작업이 오래걸릴 수 있음. salt처리를 통해 
    • BCryptPasswordEncoder 는 생성할때 strength(4~31)와 random 값을 줄 수 있는데,
      특별히 지정하지 않으면 strength 는 10을 사용하고, random값은 자체적으로 SecureRandom을 주입해준다.
	public BCryptPasswordEncoder(BCryptVersion version, int strength, SecureRandom random) {
		if (strength != -1 && (strength < BCrypt.MIN_LOG_ROUNDS || strength > BCrypt.MAX_LOG_ROUNDS)) {
			throw new IllegalArgumentException("Bad strength");
		}
		this.version = version;
		this.strength = (strength == -1) ? 10 : strength;
		this.random = random;
	}

	private String getSalt() {
		if (this.random != null) {
			return BCrypt.gensalt(this.version.getVersion(), this.strength, this.random);
		}
		return BCrypt.gensalt(this.version.getVersion(), this.strength);
	}
    

	public static String gensalt(String prefix, int log_rounds) throws IllegalArgumentException {
		return gensalt(prefix, log_rounds, new SecureRandom());
	}
  • UserDetailsService 를 구현한 Bean을 등록해줘야 한다
@RequiredArgsConstructor
@Service
public class AuthorizationService implements UserDetailsService {

    private final UserRepository userRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userRepository.findById(username).get();
        Set<GrantedAuthority> grantedAuthority = new HashSet<>();
        grantedAuthority.add(new SimpleGrantedAuthority(user.getRoleKey()));
        return new org.springframework.security.core.userdetails.User(user.getUserId(), user.getPassword(), grantedAuthority);
    }
}
  • 추가로 로그인 성공시 동작을 구현할 수 있다. AuthenticationSuccessHandler
@RequiredArgsConstructor
@Service
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

	private final HttpSession httpSession;
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
		Authentication authentication) throws IOException, ServletException {
		UserDetails userDetails = (UserDetails) authentication.getPrincipal();
		httpSession.setAttribute("login_user", userDetails.getUsername());
		response.sendRedirect("redirect:/");
	}
}
반응형