Spring 安全中的自动身份验证

Auto-Authentication in Spring Security

我有一个安全的 Spring MVC 项目。我想在成功创建新帐户后自动授权用户。这通常在创建新帐户的地方完成,如下所示:

@Controller
@RequestMapping("/spitter")
public class SpitterController {

...
@Inject AuthenticationManager authMgr;
@Inject AccountService accountService;
...

  @RequestMapping(value="/register", method=POST)
  public String processRegistration(
        @ModelAttribute("spitter") @Valid Spitter form,
        BindingResult result) {

        convertPasswordError(result);

        String psswd = form.getPassword();
        accountService.registerAccount(toAccount(form), psswd, result);

        // Auto-Authentication
        Authentication authRequest = 
          new UsernamePasswordAuthenticationToken(form.getUsername(), psswd);
        Authentication authResult = authMgr.authenticate(authRequest);
        SecurityContextHolder.getContext()
                             .setAuthentication(authResult);

      return (result.hasErrors() ? VN_REG_FORM : VN_REG_OK);
    }
 ...
}

我正在使用 Java 配置。我的安全配置文件是

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;

    @Autowired
    AccountService accountService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }     

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http
      .formLogin()
        .loginPage("/login")
      .and()
        .logout()
          .logoutSuccessUrl("/")
      .and()
      .rememberMe()
        .tokenRepository(new InMemoryTokenRepositoryImpl())
        .tokenValiditySeconds(2419200)
        .key("spittrKey")
      .and()
       .httpBasic()
         .realmName("Spittr")
      .and()
      .authorizeRequests()
        .antMatchers("/user").hasAnyAuthority("admin", "user")
        .antMatchers("/admin").hasAuthority("admin")
        .antMatchers("spitter/me").authenticated()
        .antMatchers(HttpMethod.POST, "/spittles").authenticated()
        .anyRequest().permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(new UserDetailsServiceAdapter(accountService))
          .passwordEncoder(passwordEncoder());
    }

}

如果我使用 XML 配置,我会有一个身份验证管理器元素:

<authentication-manager alias="authenticationManager">
  ...
</authentication-manager/>

之所以设置别名,是因为除 authentication-manager 元素外,还从 http 元素中获取身份验证管理器,您必须区分两者。

但是,根据我的配置,显然没有创建 AuthenticationManager:

org.springframework.beans.factory.BeanCreationException:
...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field:   org.springframework.security.authentication.AuthenticationManager   spittr.web.SpitterController.authMngr; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.authentication.AuthenticationManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.inject.Inject()}

...

这有点令人惊讶。我认为默认情况下至少会创建一个这样的 bean。我不确定最好的解决方案是什么。

默认情况下它不会作为 spring bean 公开,您需要覆盖 WebSecurityConfigurerAdapter

上的 authenticationManagerBean() 方法
@Bean(name="myAuthenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

参考:http://docs.spring.io/autorepo/docs/spring-security-javaconfig-build/1.0.0.M1/api-reference/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.html#authenticationManagerBean()