Spring Security How to check if login form credentials are valid?
How to proceed if I want to check if credentials are valid ?
For example, I want to be sure that username is valid (valid email, limited size and so on) so I can display the error to the user before even attempting to authenticate using Spring Security.
1) Make sure credentials are valid before authentication 2) Authenticate 3) Rock-n-roll
Btw, I'm using Spring Security 3.1.0 RC.
Thank you in advance for your help, Adnan
Update: Actually I'm talking about validation: making sure that username is in valid email format, or make sure that the passwords is at least 8 characters and so on. Only when I'm sure that it is in "valid" format I will submit it to the Security authentication & authorization else I just want to display the 开发者_JS百科login form again with error message (for example: "password must be at least 8 characters").
You may want to skip validation on login and only do validation on registration/edit profile/change password. When they attempt to login with a bad username/password it just won't be found.
I can see two ways to do what you want. Normally the login page POSTs to /j_spring_security_check with j_username and j_password. The UsernamePasswordAuthenticationFilter intercepts this POST and delegates to the AuthenticationManager and its AuthenticationProviders (usually the DaoAuthenticationProvider).
If you really want to do validation before it hits any Spring Security code you will need to add a Filter before the UsernamePasswordAuthenticationFilter and do your validation there.
Alternatively, subclass DaoAuthenticationProvider and override retreiveUser(). In retrieveUser() do your extra validation, throwing an exception if the validation fails.
Configure your subclass as the authentication provider like so:
<authentication-manager>
<authentication-provider ref='myAuthenticationProvider'/>
</authentication-manager>
If your environment supports Servlet 3.0+, you can use HttpServletRequest.login(username, password)
in your controller method.
Alright, I found a way to validate form fields using hibernate validator annotations @Email & NotNull and so on:
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
public class LoginForm
{
@Email
@Size(min = 4, max = 128)
private String username;
@NotBlank
@Size(min = 4, max = 128)
private String password;
...
}
The Security part was a bit tricky because I had to manually authenticate against authenticationManager and the Security Context didn't want to update current session:
@Autowired
@Qualifier("authenticationManager")
private AuthenticationManager authenticationManager;
@RequestMapping(method = RequestMethod.POST)
public String processForm(@Valid LoginForm loginForm, BindingResult result, HttpServletRequest request, Model model)
{
// Display errors in loginForm if not valid
if (result.hasErrors())
return "login";
try
{
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginForm.getUsername(), loginForm.getPassword());
Authentication auth = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(auth);
// for some reason, security context is NOT setting the auth key in session
// so I had to put it here myself!
HttpSession session = request.getSession();
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
return "redirect:/index";
}
catch (AuthenticationException e)
{
SecurityContextHolder.getContext().setAuthentication(null);
String errorMessage = e.getLocalizedMessage();
model.addAttribute("errorMessage", errorMessage);
return "loginerror";
}
}
Be sure to put alias for authentication-manager in order to be able to autowire it <security:authentication-manager alias="authenticationManager">
Hope that helps someone :)
精彩评论