如何更新auditorAware中的身份验证

huangapple go评论53阅读模式
英文:

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 之前调用了 authenticationauthentication 对象始终为 null,并且在稍后在 doFilter 中设置时不会更新。当我更新数据库中的行时,createdBylastModifiedBy 始终为 null。

我的 doFilter 似乎在处理 HTTP 请求时被调用。

我按照教程学习了 Spring Security,但是经过几个小时的故障排除并遵循了许多类似的教程,仍然无法弄清楚如何按顺序正确设置身份验证,以便在更新行时 Spring 会自动更新 lastModifiedBycreatedBy

英文:
    @Configuration
    @EnableJpaAuditing(auditorAwareRef = &quot;auditorProvider&quot;)
    public class JpaAuditingConfiguration {
	
      @Bean
      @Scope(value= ConfigurableBeanFactory.SCOPE_PROTOTYPE)
      public AuditorAware&lt;String&gt; auditorProvider() {

    	Authentication authentication 
             = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            return () -&gt; Optional.&lt;String&gt;empty();
        }
        return () -&gt; 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(&quot;/logout/success&quot;)
		        .and().authorizeRequests()
				.antMatchers(HttpMethod.POST, &quot;/login&quot;).permitAll()
				.antMatchers(HttpMethod.GET, &quot;/logout/**&quot;).permitAll()
				.anyRequest().authenticated().and()
				// Filter for the api/login requests
				.addFilterBefore(new LoginFilter(&quot;/login&quot;, 
                                     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 the SecurityContextHolder.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&lt;String&gt; auditorProvider() {

		return () -&gt; {
			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.

huangapple
  • 本文由 发表于 2020年8月1日 20:11:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/63205055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定