我是Spring的新手,所以不完全了解UserDetailsService的工作原理。
我希望我的登录表单的行为方式与我的注册表单相同。但是,相反,当使用登录详细信息发送post请求时,UserDetailsService类似乎首先执行。有人可以解释UserDetailsService如何工作(即当它被调用时)以及如何更改我的安全配置以在我的控制器POST方法中执行什么操作以进行登录(就像注册时一样)。
控制器:
@Controller
public class controller{
@RequestMapping(value = "/signup", method = RequestMethod.POST)
public String registration(@ModelAttribute("userForm") final User userForm, final BindingResult bindingResult) {
LOG.debug("Signing up with user: {}", userForm);
signUpValidationService.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "login/Signup";
}
userService.saveUser(userForm);
userService.autologin(userForm.getEmail(), userForm.getPassword());
return "about/Home";
}
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@ModelAttribute("userForm") final User userForm, final BindingResult bindingResult) {
LOG.debug("Logging in with user: {}", userForm);
loginValidationService.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "login/Login";
}
userService.autologin(userForm.getEmail(), userForm.getPassword());
LOG.debug("Successfully logged in with user: {}", userForm.getFirstName());
return "about/Home";
}
}
我的安全配置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig
extends WebSecurityConfigurerAdapter {
/**
* {@inheritDoc}
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/", "/home", "/about")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.successHandler(successHandler())
.permitAll()
.and()
.logout().deleteCookies("JSESSIONID")
.logoutUrl("/logout")
.logoutSuccessUrl("/home")
.permitAll()
.and()
.rememberMe().key("uniqueAndSecret").tokenValiditySeconds(86400)
.and()
.sessionManagement()
.sessionFixation().migrateSession()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/invalid_session")
.maximumSessions(2)
.expiredUrl("/expired_session");
}
/**
* User login validation configuration.
*
* @param auth
* {@link AuthenticationManagerBuilder}
* @param userDetailsService
* {@link UserDetailsService}
* @throws Exception
* {@link Exception}
*/
@Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth, final UserDetailsService userDetailsService)
throws
Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
/**
* Handles login success configuration policy.
*
* @return {@link AuthenticationSuccessHandler}
*/
private final AuthenticationSuccessHandler successHandler() {
return new UrlAuthenticationSuccessHandler();
}
/**
* Sets security evaluation context.
*
* @return {@link SecurityEvaluationContextExtension}
*/
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
答案 0 :(得分:3)
Spring安全自动检测你的yourOwnuserDetailsService,它实现了UserDetailsService,当用户在登录界面输入用户名和密码并点击登录按钮时。输入的信息将放入名为身份验证的对象中,该对象将传递给 AuthenticationManager 的身份验证方法。此方法将遍历所有已配置的 AuthenticationProviders 并调用其authenticate方法,并传入Authentication对象。每个 AuthenticationProvider 都会调用其配置的 UserDetailsService 的 loadUserByUserName 方法。
你不需要明确地调用它,如果你需要在Spring安全捕获它之前需要捕获Spring Security登录表单,Spring安全会处理它,here是详细信息
您可以使用常规Spring Security功能执行此操作。步骤是:
实现自定义WebAuthenticationDetailsSource和WebAuthenticationDetails。 WebAuthenticationDetails将捕获 您要验证的额外表单字段。
注意:在Spring 3.0中,您需要使用BeanPostProcessor将WebAuthenticationDetailsSource配置为 UsernamePasswordAuthenticationFilter。在Spring 3.1中,您可以执行此操作 直接在命名空间配置中。
实现自定义AuthenticationProvider并在authenticate()中检查WebAuthenticationDetails,抛出一个 AuthenticationException如果验证失败。在您的登录页面中检查 对于这个例外。
或者,您可以创建一个进行验证的Filter,并在Spring Security过滤器之前添加它。
此外,如果您需要验证参数,则可以使用extends UsernamePasswordAuthenticationFilter
进行检查。int n;
cin >> n;
vector <int> graph[n], visited(n);
for (int i = 0; i < n - 1; ++i)
{
int st, en;
cin >> st >> en;
st--;
en--;
graph[st].push_back(en);
graph[en].push_back(st);
}
int st, en;
cin >> st >> en;
st--, en--;
queue <pair <int, int> > q;
q.push({st, 0});
visited[st] = 1;
while (!q.empty())
{
auto top = q.front();
if (top.first == en)
return top.second;
q.pop();
for (auto & x : graph[top.first])
{
if(!visited[x])
{
q.push({x, top.second + 1});
visited[x] = 1;
}
}
}