Spring Security3 自定义登录,验证码登录

Security3 安全架构 这里主要说的就是spring-security.xml 配置 因为网上这个资料确实很少

首先 pom  

org.springframework.security 的包 我现在版本是3.1.4的  注意依赖都要导入的 包名就不写了!

web.xml

security 的过滤器链


   springSecurityFilterChain
   
      org.springframework.web.filter.DelegatingFilterProxy
   


   springSecurityFilterChain
   /*

现在开始正题

spring-security.xml 配置  这个配置主要是用来重写attemptAuthentication方法的 这个是重点


        
        
        
         
               
        
            
        
    
     
           
          
          
    
               
             
        
    
     
     

   //UsernamePasswordAuthenticationFilter的实现 重写 attemptAuthentication方法 逻辑随意修改

package com.hearing.cloud.background.loginFilter;

import com.hearing.cloud.background.model.OrdinaryUser;
import com.hearing.cloud.background.model.User;
import com.hearing.cloud.background.service.IOrdinaryUserManager;
import com.hearing.cloud.background.service.IUserManager;
import com.hearing.cloud.background.util.ActionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

//这里一般都是继承UsernamePasswordAuthenticationFilter 但是 我这里没有继承他  我继承了他爷爷 AbstractAuthenticationProcessingFilter
public class LoginFilterAuthentication extends AbstractAuthenticationProcessingFilter {


    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
    /** @deprecated */
    @Deprecated
    public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";
    private String usernameParameter = "j_username";
    private String passwordParameter = "j_password";
    private boolean postOnly = true;
    private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
    //继承爷爷的原因是 我重新构造这个参数, 默认的是 /j_spring_security_check  我认为太丑
    public LoginFilterAuthentication() {
        super("/home");
    }
    @Autowired
    private IOrdinaryUserManager ordinaryUserManager;
    @Autowired
    private IUserManager iUserManager;
    @Autowired
    private ShaPasswordEncoder shaPasswordEncoder;
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (this.postOnly &&!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        UsernamePasswordAuthenticationToken authRequest=null;
        //前端的选择,0是用户名登录, 1是验证码登录
        Map map = ActionUtil.getParameters(request);
        String selects=map.get("selects");

        if("0".equals(selects)){ //正常登陆 因为我们没有在xml中配置加密,所以我们手动加密,更灵活一些 
           authRequest = new UsernamePasswordAuthenticationToken(账号, 密码);
        }else{ //电话号码登录 密码就不用加密了 直接登录
            //验证码对比结果
            boolean falg=true;
            if(falg) { //验证通过
                    authRequest = new UsernamePasswordAuthenticationToken(账号, 密码);
            }else{//验证失败 我们要手动抛出一个异常,在后面的验证失败类中去捕获
                authRequest = new UsernamePasswordAuthenticationToken("", "");
                throw new AuthenticationServiceException("验证码错误");
            }
            request.getSession().removeAttribute("phone");
        }
        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);
        // 执行校验(使用DaoAuthenticationProvider进行校验)
        return this.getAuthenticationManager().authenticate(authRequest);
    }



    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(this.passwordParameter);
    }

    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(this.usernameParameter);
    }

    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    public void setUsernameParameter(String usernameParameter) {
        Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
        this.usernameParameter = usernameParameter;
    }

    public void setPasswordParameter(String passwordParameter) {
        Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
        this.passwordParameter = passwordParameter;
    }

    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }




}

   //查询用户的实现 实现 UserDetailsService的 loadUserByUsername方法 返回一个UserDetails  

@Repository(value = "userDaoImpl")
public class UserDaoImpl extends GenericDaoHibernate implements IUserDao, UserDetailsService {

    /**
    * 用户登录
    */
    @SuppressWarnings({"deprecation", "rawtypes"})
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException         
    {
         //逻辑我就不写了  你们想怎么写就怎么写,记得查询出来的 user 转换成 UserDetails  
    }
}

 

  //验证成功的方法 需要继承SimpleUrlAuthenticationSuccessHandler和实现AuthenticationSuccessHandler接口

package com.hearing.cloud.background.loginFilter;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.util.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    //我重写的目的 1.主要是这个位置 因为我要访问我的 跳转首页方法的逻辑接口
    //2.是如果不改这里 登录会有两个后果,1.登录后关闭页面,在次打开,页面会显示路径无法加载,2. 
    //第一次登录成功跳转页面是你首页加载的第一个js页面而不是首页,请认真对待
    @Value("/") 
    private String defaultTargetUrl;

    private RequestCache requestCache = new HttpSessionRequestCache();
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        SavedRequest savedRequest = this.requestCache.getRequest(request, response);
        if(savedRequest == null) {
            super.onAuthenticationSuccess(request, response, authentication);
        } else {
            String targetUrlParameter = this.getTargetUrlParameter();
            if(!this.isAlwaysUseDefaultTargetUrl() && (targetUrlParameter == null || !StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
                this.clearAuthenticationAttributes(request);
                this.logger.debug("Redirecting to DefaultSavedRequest Url: " + defaultTargetUrl);
                this.getRedirectStrategy().sendRedirect(request, response, defaultTargetUrl);
            } else {
                this.requestCache.removeRequest(request, response);
                super.onAuthenticationSuccess(request, response, authentication);
            }
        }
    }
    public void setRequestCache(RequestCache requestCache) {
        this.requestCache = requestCache;
    }
}

 //验证失败  需要实现AuthenticationFailureHandler 接口

package com.hearing.cloud.background.loginFilter;


import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;


public class LoginFailureHandler implements AuthenticationFailureHandler {

    private String defaultFailureUrl;
    private boolean forwardToDestination = false;
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    private boolean allowSessionCreation = true;

    public LoginFailureHandler() {
    }

    public LoginFailureHandler(String defaultFailureUrl) {
        this.setDefaultFailureUrl(defaultFailureUrl);
    }

    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        if(this.defaultFailureUrl == null) {
            if("验证码错误".equals(e.getMessage())){
                redirectStrategy.sendRedirect(request, response, "/doctorLogin?error=3");
            }else{
                redirectStrategy.sendRedirect(request, response, "/doctorLogin?error=1");
            }
        } else {
            this.saveException(request, e);
            if(this.forwardToDestination) {
                request.getRequestDispatcher(this.defaultFailureUrl).forward(request, response);
            } else {
                this.redirectStrategy.sendRedirect(request, response, this.defaultFailureUrl);
            }
        }
    }
    public void setDefaultFailureUrl(String defaultFailureUrl) {
        Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultFailureUrl), "\'" + defaultFailureUrl + "\' is not a valid redirect URL");
        this.defaultFailureUrl = defaultFailureUrl;
    }
    protected final void saveException(HttpServletRequest request, AuthenticationException exception) {
        if(this.forwardToDestination) {
            request.setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);
        } else {
            HttpSession session = request.getSession(false);
            if(session != null || this.allowSessionCreation) {
                request.getSession().setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);
            }
        }

    }
    protected boolean isUseForward() {
        return this.forwardToDestination;
    }

    public void setUseForward(boolean forwardToDestination) {
        this.forwardToDestination = forwardToDestination;
    }

    protected boolean isAllowSessionCreation() {
        return this.allowSessionCreation;
    }

    public void setAllowSessionCreation(boolean allowSessionCreation) {
        this.allowSessionCreation = allowSessionCreation;
    }


}

你可能感兴趣的:(Spring Security3 自定义登录,验证码登录)