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();
}
我有一个安全的 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();
}