英文:
How to update authentication in auditorAware
问题
@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaAuditingConfiguration {
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public AuditorAware<String> auditorProvider() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return () -> Optional.<String>empty();
}
return () -> Optional.of(authentication.getName());
}
public static void main(String[] args) {
SpringApplication.run(JpaAuditingConfiguration.class, args);
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailServiceImpl userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/logout/success")
.and().authorizeRequests()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.antMatchers(HttpMethod.GET, "/logout/**").permitAll()
.anyRequest().authenticated().and()
.addFilterBefore(new LoginFilter("/login",
authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new AuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
}
public class AuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest) request);
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
filterChain.doFilter(request, response);
}
}
auditorProvider
看起来只在应用程序启动时被调用。doFilter
中在设置 authentication
之前调用了 authentication
。authentication
对象始终为 null,并且在稍后在 doFilter
中设置时不会更新。当我更新数据库中的行时,createdBy
和 lastModifiedBy
始终为 null。
我的 doFilter
似乎在处理 HTTP 请求时被调用。
我按照教程学习了 Spring Security,但是经过几个小时的故障排除并遵循了许多类似的教程,仍然无法弄清楚如何按顺序正确设置身份验证,以便在更新行时 Spring 会自动更新 lastModifiedBy
和 createdBy
。
英文:
@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaAuditingConfiguration {
@Bean
@Scope(value= ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public AuditorAware<String> auditorProvider() {
Authentication authentication
= SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return () -> Optional.<String>empty();
}
return () -> Optional.of(authentication.getName());
}
public static void main(String[] args) {
SpringApplication.run(JpaAuditingConfiguration.class, args);
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailServiceImpl userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/logout/success")
.and().authorizeRequests()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.antMatchers(HttpMethod.GET, "/logout/**").permitAll()
.anyRequest().authenticated().and()
// Filter for the api/login requests
.addFilterBefore(new LoginFilter("/login",
authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// Filter for other requests to check JWT in header
.addFilterBefore(new AuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
public class AuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
Authentication authentication
= AuthenticationService
.getAuthentication((HttpServletRequest)request);
SecurityContext securityContext
= SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
filterChain.doFilter(request, response);
}
}
auditorProvider
seems to be called only once when application starts. authentication
is called before it is set in doFilter
. authentication
object is always null and doesn't update when it's set later in doFilter
. When I update a row in db, createdBy
and lastModifiedBy
are always null.
My doFilter
seems to be called when an HTTP request is processed.
I followed a tutorial to learn spring security, but after troubleshooting for a few hours and followed through many similar tutorial, still can't figure out how to properly set the authentication in sequence so when I update a row, spring will update lastModifiedBy
and createdBy
automatically.
答案1
得分: 2
- 问题在于您正在创建一个匿名的
AuditorAware
,但在方法体外部评估了SecurityContextHolder.getContext().getAuthentication()
,因此在创建时的任何内容都将保留在方法体内。
@Bean
@Scope(value= ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public AuditorAware<String> auditorProvider() {
return () -> {
Authentication authentication
= SecurityContextHolder.getContext().getAuthentication();
return Optional.ofNullable(authentication)
.map(Authentication::getName);
};
}
- 您可以说,您拥有
SCOPE_PROTOTYPE
,但如果它被自动装配到框架使用的单例实例中,那么它将是无用的。
英文:
- Your issue is that you are creating an anonymous
AuditorAware
but you are evaluating theSecurityContextHolder.getContext().getAuthentication()
outside the body so whatever at that creation time will be kept inside the body.
@Bean
@Scope(value= ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public AuditorAware<String> auditorProvider() {
return () -> {
Authentication authentication
= SecurityContextHolder.getContext().getAuthentication();
return Optional.ofNullable(authentication)
.map(Authentication::getName);
};
}
- You could say, you have
SCOPE_PROTOTYPE
but it is useless if it was autowired into a singleton instance that framework uses.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论