我们正在尝试使用令牌身份验证来使用@PreAuthorize。
当我们尝试使用@PreAuthorize时,SpringSecurity会在调用API之前弹出登录页面。我们不需要该页面,因为我们有自己的身份验证过程。
为了跳过该页面,我们添加了 @SpringBootApplication(exclusion = { SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class }) 在我们的主类上。
在此之后,登录页面被跳过,但是当我们触发它们时,我们所有的 API 都会给出错误,即身份验证需要在上下文中存在。
为此我们做了以下更改
@Configuration
public class MethodSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().addFilter(new AuthFilter(authenticationManagerBean())).authorizeRequests().anyRequest().permitAll();
}
}
@Component
public class AuthFilter implements Filter {
private AuthenticationManager authenticationManager;
public AuthFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain)
throws IOException, ServletException {
final String authorizationHeader = ((HttpServletRequest) request).getHeader("Authorization");
System.out.println("===========Filter called================");
final Authentication authentication = authenticationManager
.authenticate(SecurityContextHolder.getContext().getAuthentication());
System.out.println("===========Authentication================"+authentication);
if (authentication != null && !(authentication instanceof AnonymousAuthenticationToken)
&& authentication.isAuthenticated()) {
// set authentication in security context holder
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterchain.doFilter(request, response);
}
}
现在,当我收到错误消息说 AuthenticationManager 不存在任何 bean 时。
我尝试了许多其他方法,但豆子仍然没有注入过滤器中
你能对此发表评论吗?
@Configuration
public class MethodSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().addFilter(new AuthFilter(authenticationManagerBean())).authorizeRequests().anyRequest().permitAll();
}
}
@Component
public class AuthFilter implements Filter {
@Autowired //--->use this
private AuthenticationManager authenticationManager;
public AuthFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain)
throws IOException, ServletException {
final String authorizationHeader = ((HttpServletRequest) request).getHeader("Authorization");
System.out.println("===========Filter called================");
final Authentication authentication = authenticationManager
.authenticate(SecurityContextHolder.getContext().getAuthentication());
System.out.println("===========Authentication================"+authentication);
if (authentication != null && !(authentication instanceof AnonymousAuthenticationToken)
&& authentication.isAuthenticated()) {
// set authentication in security context holder
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterchain.doFilter(request, response);
}
}
尝试这样的事情可能会有所帮助:
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
您还可以参考此 How To Inject AuthenticationManager using Java Configuration in a Custom Filter
像这样尝试一次
@Configuration
public class MethodSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
AuthFilter authFilter;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().addFilter(authFilter).authorizeRequests().anyRequest().permitAll();//change is here
}
}
@Component
public class AuthFilter implements Filter {
private AuthenticationManager authenticationManager;
public AuthFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain)
throws IOException, ServletException {
final String authorizationHeader = ((HttpServletRequest) request).getHeader("Authorization");
System.out.println("===========Filter called================");
final Authentication authentication = authenticationManager
.authenticate(SecurityContextHolder.getContext().getAuthentication());
System.out.println("===========Authentication================"+authentication);
if (authentication != null && !(authentication instanceof AnonymousAuthenticationToken)
&& authentication.isAuthenticated()) {
// set authentication in security context holder
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterchain.doFilter(request, response);
}
}
不要使用 spring bean AuthFilter 创建 auth 过滤器的 Java 对象
这个问题发生是因为 Spring Security 新版本做了一些更改
更改此方法:
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
对此:
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
并更改此:
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().addFilter(authFilter).authorizeRequests().anyRequest().permitAll();
}
这个风格
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> authorize.requestMatchers("/").authenticated().anyRequest().permitAll())
.csrf(AbstractHttpConfigurer::disable)
return http.build();
}
HttpSecurity 的 configure() 方法被 filterChain 方法取代,如官方网站上所述: