Spring Security3.1登陆验证

一、前言

      在上一篇http://blog.csdn.net/k10509806/archive/2011/04/28/6369131.aspx文章中,提到的MyUserDetailServiceImpl获取用户权限,在用户没有登陆的时候,Spring Security会让我们自动跳转到默认的登陆界面,但在实际应用绝大多数是用我们自己的登陆界面的,其中就包括一些我们自己的逻辑,比如验证码。所以本人又研究一下,终于摸清了一些如何配置自己的登陆界面的办法。在这里献丑了。

 

二、Spring Security的过滤器

      通过DEBUG可以看到Spring Security的Filter的顺序

Security filter chain: [
  ConcurrentSessionFilter
  SecurityContextPersistenceFilter
  LogoutFilter
  MyUsernamePasswordAuthenticationFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  RememberMeAuthenticationFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  MySecurityFilter
  FilterSecurityInterceptor
]

Spring Security的登陆验证用的就是MyUsernamePasswordAuthenticationFilter,所以要实现我们自己的验证,可以写一个类并继承MyUsernamePasswordAuthenticationFilter类,重写attemptAuthentication方法。

 

三、applicationContext-Security.xml配置

这里特别要说明一下,我们的标签不能配置auto-config,因为这样配置后,依然会采用Spring Security的Filter Chain会与下面我们配的custom-filter冲突,最好会抛异常。还有配置一个切入点entry-point-ref="authenticationProcessingFilterEntryPoint",为了在未登陆的时候,跳转到哪个页面,不配也会抛异常。

  position表示替换掉Spring Security原来默认的登陆验证Filter。

 

四、MyUsernamePasswordAuthenticationFilter

package com.huaxin.security; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang.xwork.StringUtils; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.WebAttributes; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import com.huaxin.bean.Users; import com.huaxin.dao.UsersDao; /* * * UsernamePasswordAuthenticationFilter源码 attemptAuthentication this.getAuthenticationManager() ProviderManager.java authenticate(UsernamePasswordAuthenticationToken authRequest) AbstractUserDetailsAuthenticationProvider.java authenticate(Authentication authentication) P155 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); DaoAuthenticationProvider.java P86 loadUserByUsername */ public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{ public static final String VALIDATE_CODE = "validateCode"; public static final String USERNAME = "username"; public static final String PASSWORD = "password"; private UsersDao usersDao; public UsersDao getUsersDao() { return usersDao; } public void setUsersDao(UsersDao usersDao) { this.usersDao = usersDao; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (!request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } //检测验证码 checkValidateCode(request); String username = obtainUsername(request); String password = obtainPassword(request); //验证用户账号与密码是否对应 username = username.trim(); Users users = this.usersDao.findByName(username); if(users == null || !users.getPassword().equals(password)) { /* 在我们配置的simpleUrlAuthenticationFailureHandler处理登录失败的处理类在这么一段 这样我们可以在登录失败后,向用户提供相应的信息。 if (forwardToDestination) { request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); } else { HttpSession session = request.getSession(false); if (session != null || allowSessionCreation) { request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); } } */ throw new AuthenticationServiceException("用户名或者密码错误!"); } //UsernamePasswordAuthenticationToken实现 Authentication UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // Place the last username attempted into HttpSession for views // 允许子类设置详细属性 setDetails(request, authRequest); // 运行UserDetailsService的loadUserByUsername 再次封装Authentication return this.getAuthenticationManager().authenticate(authRequest); } protected void checkValidateCode(HttpServletRequest request) { HttpSession session = request.getSession(); String sessionValidateCode = obtainSessionValidateCode(session); //让上一次的验证码失效 session.setAttribute(VALIDATE_CODE, null); String validateCodeParameter = obtainValidateCodeParameter(request); if (StringUtils.isEmpty(validateCodeParameter) || !sessionValidateCode.equalsIgnoreCase(validateCodeParameter)) { throw new AuthenticationServiceException("验证码错误!"); } } private String obtainValidateCodeParameter(HttpServletRequest request) { Object obj = request.getParameter(VALIDATE_CODE); return null == obj ? "" : obj.toString(); } protected String obtainSessionValidateCode(HttpSession session) { Object obj = session.getAttribute(VALIDATE_CODE); return null == obj ? "" : obj.toString(); } @Override protected String obtainUsername(HttpServletRequest request) { Object obj = request.getParameter(USERNAME); return null == obj ? "" : obj.toString(); } @Override protected String obtainPassword(HttpServletRequest request) { Object obj = request.getParameter(PASSWORD); return null == obj ? "" : obj.toString(); } }

有时间,大家看看源码吧。

 

五、login.jsp

<%=session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) %>

Account:
Password:

 

六、完了,源码大家可以看下我上一篇文章http://blog.csdn.net/k10509806/archive/2011/04/28/6369131.aspx

 

你可能感兴趣的:(spring)