스프링 보안:Spring Boot 2.7.0에서 사용되지 않는 Web Security Configurer Adapter
업데이트를 시도하고 있습니다.WebSecurityConfigurerAdapter
더 이상 권장되지 않습니다.클래스는 다음과 같이 설정됩니다.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UsuariService userDetailsService;
@Autowired
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
.antMatchers("/api/auth/**").permitAll().antMatchers("/api/test/**").permitAll().antMatchers("/api/v1/**").permitAll().anyRequest()
.authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
이 시점에서,WebSecurityConfigurerAdapter
같은 클래스를 다음과 같이 재정의합니다.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
@Autowired
UsuariService userDetailsService;
@Autowired
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@Bean
AuthenticationManager authenticationManager(AuthenticationManagerBuilder builder) throws Exception {
return builder.userDetailsService(userDetailsService).passwordEncoder(encoder()).and().build();
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.antMatchers("/api/v1/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
그러나 유감스럽게도 다음과 같은 오류가 발생합니다.
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration':
Unsatisfied dependency expressed through method 'setFilterChains' parameter 0;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'filterChain' defined in class path resource [cit/base/app/security/WebSecurityConfig.class]:
Unsatisfied dependency expressed through method 'filterChain' parameter 0;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity' defined in class path resource [org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class]:
Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.security.config.annotation.web.builders.HttpSecurity]: Factory method 'httpSecurity' threw exception;
nested exception is java.lang.IllegalStateException:
Cannot apply org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$EnableGlobalAuthenticationAutowiredConfigurer@3fdc705c to already built object
어떤 도움이라도 주시면 감사하겠습니다.
방법을 업데이트했습니다.이것은 Web Security Config 클래스이며 메서드는 다음과 같이 변경됩니다.
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
다음과 같이 되어 있습니다.
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
설명:AuthenticationManagerBuilder를 주입한 이전 버전에서는 userDetailsService, passwordEncoder를 설정하고 구축합니다.단, authenticationManager는 이 단계에서 이미 작성되어 있습니다.원하는 방식으로 생성됩니다(userDetailsService 및 passwordEncoder 사용).
다음으로 HttpSecurity의 configure() 메서드는 공식 사이트(https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter에서 설명하고 있는 filterChain 메서드로 대체됩니다.
import com.myproject.UrlMapping;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class SecurityConfig {
private final UserDetailsService userDetailsService;
private final AuthEntryPointJwt unauthorizedHandler;
private final AuthTokenFilter authenticationJwtTokenFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers(UrlMapping.AUTH + UrlMapping.SIGN_UP).permitAll()
.antMatchers(UrlMapping.AUTH + UrlMapping.LOGIN).permitAll()
.antMatchers(UrlMapping.VALIDATE_JWT).permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*");
}
};
}
}
내 대답이 너에게 도움이 됐으면 좋겠어!또한 build.gradle 파일에 다음과 같이 추가하였습니다.
implementation 'javax.xml.bind:jaxb-api:2.3.0'
이 구성이 다음 기간 동안 작동하기를 바랍니다.UserDetailsService
,AuthenticationManagerBuilder
그리고.AuthenticationManager
.
@Configuration
public class BeanConfiguration {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Configuration
public class SpringSecurityConfiguration {
AuthenticationManager authenticationManager;
@Autowired
UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.userDetailsService(userDetailsService);
authenticationManager = authenticationManagerBuilder.build();
http.csrf().disable().cors().disable().authorizeHttpRequests().antMatchers("/api/v1/account/register", "/api/v1/account/auth").permitAll()
.anyRequest().authenticated()
.and()
.authenticationManager(authenticationManager)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
@Component
class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private AccountService accountService;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Account account = accountService.findAccountByEmail(email);
return new UserPrincipalImp(account);
}
// ...
}
다음과 같이 파일을 변경합니다.
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class SpringSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable().authorizeHttpRequests()
.requestMatchers("/user/register").permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer();
return http.build();
}
}
WebSecurityConfigrAdapter를 확장하지 않고 SecurityConfig 클래스를 완전히 구현하는 방법은 다음과 같습니다.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
UserDetailsService userDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception{
// We don't need CSRF for this example
httpSecurity.csrf().disable()
// don't authenticate this particular request
.authorizeHttpRequests().antMatchers("/authenticate").permitAll()
// all other requests need to be authenticated
.anyRequest().authenticated().and()
// make sure we use stateless session; session won't be used to
// store user's state.
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
이 방법은 제 경우 가장 간단한 방법은 SecurityFilterChain 함수로 직접 userDetailService 클래스를 전달하는 것입니다.
주의:http.userDetailsService(customUserDetailService);
BCrypt Password Encoder 클래스는 설정에서 @Bean 메서드를 사용할 수 있는 경우 자동으로 암호 인코더로 자동 설정됩니다.
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
코드:
package com.example.blogapi.config;
import com.example.blogapi.security.CustomUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {
@Autowired
private CustomUserDetailService customUserDetailService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(
(authz) -> authz.anyRequest()
.authenticated())
.httpBasic(Customizer.withDefaults())
.userDetailsService(customUserDetailService);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
- 보안 설정
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
int rounds = 12;
return new BCryptPasswordEncoder(rounds);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.httpBasic()
.and()
.authorizeHttpRequests()
/*.requestMatchers("/user/**").hasRole("USER")*/
.requestMatchers("/user/**", "/user/info/**").hasAuthority("USER")
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);;
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(UserDetailsService customUserDetailsService) {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(customUserDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
List<AuthenticationProvider> providers = List.of(authProvider);
return new ProviderManager(providers);
}
}
- 서비스
@Service
@RequiredArgsConstructor
public class CustomUserDetailService implements UserDetailsService {
private final CustomerRepository customerRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final CustomerModel customer = customerRepository.findByEmail(username); /*email*/
Set<UserRole> roles = new HashSet<>();
roles.add(new UserRole("USER"));
roles.add(new UserRole("ADMIN"));
if (customer == null) {
throw new UsernameNotFoundException(username);
}
String email = customer.email();
String password = customer.password();
return User
.withUsername(email)
.password(password)
/*.roles("USER")*/ /*Into a Security filter must be expression -> hasRole()*/
.authorities(convertAuthorities(roles))
.build();
}
private Set<GrantedAuthority> convertAuthorities(Set<UserRole> userRoles) {
Set<GrantedAuthority> authorities=new HashSet<>();
for (UserRole userRole : userRoles) {
authorities.add(new SimpleGrantedAuthority(userRole.nameRole()));
}
return authorities;
}
}
클래스를 다음과 같이 수정합니다.
@Configuration
@EnableWebSecurity
public class Securityconfiguration{
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.withUsername("user1")
.password(passwordEncoder().encode("user1Pass"))
.roles("USER")
.build();
UserDetails manager = User.withUsername("user2")
.password(passwordEncoder().encode("user2Pass"))
.roles("MANAGER")
.build();
UserDetails admin = User.withUsername("admin")
.password(passwordEncoder().encode("adminPass"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, manager, admin);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeHttpRequests()
.requestMatchers("/index.html").permitAll()
.requestMatchers("/profile/**").authenticated()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/management/index").hasAnyRole("ADMIN","MANAGER")
.anyRequest().authenticated()
.and()
.httpBasic();
return http.build();
}
}
언급URL : https://stackoverflow.com/questions/72381114/spring-security-upgrading-the-deprecated-websecurityconfigureradapter-in-spring
'programing' 카테고리의 다른 글
파일 기반 H2 데이터베이스를 사용하도록 스프링 부트를 구성하는 방법 (0) | 2023.03.08 |
---|---|
$resource 요청을 취소하는 방법 (0) | 2023.03.08 |
TypeScript에서 반응 상태 사용 (0) | 2023.03.08 |
스프링 부트:application.properties를 사용하여 로깅 수준을 설정하려면 어떻게 해야 합니까? (0) | 2023.03.08 |
"내 계정" 페이지를 커스터마이즈하려면 어떻게 해야 하나요? (0) | 2023.03.08 |