开发者

MVC Form based Spring Security login?

开发者 https://www.devze.com 2023-04-06 07:51 出处:网络
I have an application that uses Spring Security to control access to pages, to manage user roles (GrantedAuthority) and for ACL. The application uses the standard UsernamePasswordAuthenticationFilter

I have an application that uses Spring Security to control access to pages, to manage user roles (GrantedAuthority) and for ACL. The application uses the standard UsernamePasswordAuthenticationFilter that intercepts requests to /j_spring_security_ch开发者_如何学JAVAeck (with j_username and j_password request parameters), and using a ProviderManager it authenticates the user and on success stores it in the SecurityContextHolder.

The above is configured in the security context, using a customized UserDetailsService:

<authentication-manager alias="authenticationManager">
    <authentication-provider user-service-ref='myUserDetailsService'/>
</authentication-manager>

The above approach in my case is not optimal, for the following reasons:

  • Adding a captcha requires extra filters
  • In order to customize the login logic, I need to replace the AuthenticationProvider as well
  • showing errors in the login form is complex, since I cannot use Spring MVC's forms

My idea is to remove the interceptor based login and put all the logic inside a Spring 3 MVC controller. The pseudo-code is as following:

RequestMapping(value="/login/", method = RequestMethod.POST)
public String attemptLogin(HttpServletRequest request, HttpServletResponse response,
    @ModelAttribute("login") LoginCmd login, Model model) {

    // validate command (username, password, captcha)
    // ...

    // load user from DB
    User user = userService.loadUserByUsername(login.getUsername());

    // extra logic (check number of failed logins + other stuff)
    // ...

    // In case everything is fine, create a spring security User

    /* Instead of creating the user, read it from DB */
    org.springframework.security.core.userdetails.User authUser =
        new org.springframework.security.core.userdetails.User(
        login.getUsername() /*username*/,
        login.getPassword() /*password*/,
        true /*enabled*/,
        true /*accountNonExpired */,
        true /*credentialsNonExpired */,
        true /*accountNonLocked*/,
        new ArrayList<GrantedAuthority>() /*authorities*/
    );

    // build the AuthenticationToken
    UsernamePasswordAuthenticationToken authResult =
        new UsernamePasswordAuthenticationToken(authUser, login.getPassword(),
        authUser.getAuthorities());
    // use WebAuthenticationDetailsSource do build details
    authResult.setDetails(detailsSource.buildDetails(request));
    SecurityContextHolder.getContext().setAuthentication(authResult);

    return SUCCESS_VIEW;
}

Do you see any problem with the solution here above? Is setting the authentication inside the SecurityContextHolder enough? Am I missing something?

Comments and suggestions are welcome ;-) Thanks a lot to everyone Andrea


I went through the Spring Security code, and on successful authentication also the original code just stores the Authentication object in the SecurityContextHolder, nothing else is done.

For example, in class AbstractAuthenticationProcessingFilter (which is used by the standard login intercepting requests to /j_spring_security_check) does that:

 protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
        Authentication authResult) throws IOException, ServletException {

    if (logger.isDebugEnabled()) {
        logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
    }

    SecurityContextHolder.getContext().setAuthentication(authResult);

    rememberMeServices.loginSuccess(request, response, authResult);

    // Fire event
    if (this.eventPublisher != null) {
        eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
    }

    successHandler.onAuthenticationSuccess(request, response, authResult);
}

I implemented this on my application and everything works fine.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号