Spring Security 入门(3-11)Spring Security 的使用-自定义登录验证和回调地址

  1. 配置文件 security-ns.xml  
  2.      
  3.      <?xml version="1.0" encoding="UTF-8"?>  
  4.     <beans xmlns="http://www.springframework.org/schema/beans"  
  5.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"  
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  7.         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">  
  8.   
  9.     //需要过滤不被拦截的请求  
  10.     <security:http pattern="/openapi/**" security="none" />  
  11.     <security:http pattern="/useraccounts/userprofile.json" security="none" />  
  12.     <security:http pattern="/useraccounts/register**" security="none" />  
  13.      
  14.      //entry-point-ref 配置自定义登录  
  15.     <security:http auto-config="false" entry-point-ref="authenticationEntryPoint">  
  16.         <security:intercept-url pattern="/backManage/**" access="ROLE_BACK_USER" />  
  17.         <security:intercept-url pattern="/mall/**"       access="ROLE_BACK_USER" />  
  18.         <security:intercept-url pattern="/thirdUser/**"  access="ROLE_USER" />  
  19.         <security:intercept-url pattern="/useraccounts/**" access="ROLE_USER" />  
  20.         <security:intercept-url pattern="/cart/**.html" access="ROLE_USER" />  
  21.         <security:intercept-url pattern="/ticket/**" access="ROLE_USER,ROLE_BACK_USER" />  
  22.         <security:intercept-url pattern="/order/**" access="ROLE_USER" />  
  23.         <security:intercept-url pattern="/comment/**" access="ROLE_USER" />  
  24.         <security:intercept-url pattern="/personal/**" access="ROLE_USER" />  
  25.         <security:intercept-url pattern="/favorite/**" access="ROLE_USER" />  
  26.       
  27.         //需要替换的Filter顺序,配置自定义custom-filter时必须蔣auto-config="false",不然会报已经存在同样的过滤器错误  
  28.         <security:custom-filter ref="myLoginFilter"  position="FORM_LOGIN_FILTER" />  
  29.         //登出配置  
  30.         <security:logout logout-success-url="${local.service.url}"/>  
  31.     </security:http>  
  32.   
  33.      //密码加密工具类  
  34.     <bean id="encoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>  
  35.     //认证管理器  
  36.     <security:authentication-manager alias="authenticationManager">  
  37.         //UserDetailsService实现 主要用于用户的查询  
  38.         <security:authentication-provider user-service-ref="userLoginService">  
  39.             <security:password-encoder  ref="encoder">  
  40.             </security:password-encoder>  
  41.         </security:authentication-provider>  
  42.     </security:authentication-manager>  
  43.   
  44.     <bean id="myLoginFilter" class="com.sale114.www.sercurity.MyUsernamePasswordAuthenticationFilter">  
  45.         <property name="authenticationManager" ref="authenticationManager"/>  
  46.         <property name="authenticationFailureHandler" ref="failureHandler"/>  
  47.         <property name="authenticationSuccessHandler" ref="successHandler"/>  
  48.     </bean>  
  49.   
  50.     //成功登录后  
  51.     <bean id="successHandler" class="com.sale114.www.sercurity.MySavedRequestAwareAuthenticationSuccessHandler">  
  52.         <property name="defaultTargetUrl" value="${local.service.url}"/>  
  53.     </bean>  
  54.     //登录失败  
  55.     <bean id="failureHandler" class="com.sale114.www.sercurity.MySimpleUrlAuthenticationFailureHandler">  
  56.         <property name="defaultFailureUrl" value="${local.service.url}/login.html?validated=false"/>  
  57.     </bean>  
  58.       
  59.     <bean id="authenticationEntryPoint"  
  60.         class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">  
  61.         <property name="loginFormUrl" value="${local.service.url}/login.html" />  
  62.     </bean>  
  63. </beans>  
  64.   
  65.   
  66. 2 UserLoginServiceImpl 查询用户实现类  
  67.   
  68.      @Named("userLoginService")  
  69. public class UserLoginServiceImpl  implements UserDetailsService ,LoginService{  
  70.   
  71.     @Inject  
  72.     private UserLoginDAO userLoginDAO;  
  73.       
  74.     @Override  
  75.     public WrappedUserLogin getUserLogin() {  
  76.         try {  
  77.             WrappedUserLogin wrappedUserLogin = (WrappedUserLogin) SecurityContextHolder  
  78.                     .getContext().getAuthentication().getPrincipal();  
  79.             return wrappedUserLogin;  
  80.         } catch (Exception e) {  
  81.             return null;  
  82.         }  
  83.     }  
  84.   
  85.     @Override  
  86.     public UserDetails loadUserByUsername(String username)  
  87.             throws UsernameNotFoundException {  
  88.         System.out.println("用户名-------------"+username);  
  89.         UserLogin userLogin =  null;  
  90.         if(username != null && !"".equals(username)&& username.indexOf("@") > 0){  
  91.               userLogin = userLoginDAO.findByEmail(username);  
  92.               username = userLogin.getNick();  
  93.         }else{  
  94.             userLogin = userLoginDAO.findByNick(username);  
  95.         }  
  96.         System.out.println("user is null ---"+userLogin.getUserType());  
  97.         String nick = userLogin.getNick();  
  98.         String email = userLogin.getEmail();  
  99.         String mobile = userLogin.getMobile();  
  100.         int userType = userLogin.getUserType();  
  101.         List<GrantedAuthority> resultAuths = new ArrayList<GrantedAuthority>();  
  102.           
  103.   
  104.         // 前台用户  
  105.         if (userType == 1) {  
  106.             resultAuths.add(new SimpleGrantedAuthority("ROLE_USER"));  
  107.         } else {  
  108.             resultAuths.add(new SimpleGrantedAuthority("ROLE_BACK_USER"));  
  109.         }  
  110.           
  111.         return new WrappedUserLogin(userLogin.getId(), email, nick, mobile, userLogin.getPassword(), userType,resultAuths);  
  112.     }  
  113.   
  114. }  
  115.   
  116. 3 重写用户名密码验证  
  117.      public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{  
  118.         //用户名  
  119.         public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";  
  120.         //密码  
  121.         public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";  
  122.         //需要回调的URL 自定义参数  
  123.         public static final String SPRING_SECURITY_FORM_REDERICT_KEY = "spring-security-redirect";  
  124.           
  125.         /**  
  126.          * @deprecated If you want to retain the username, cache it in a customized {@code AuthenticationFailureHandler}  
  127.          */  
  128.         @Deprecated  
  129.         public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";  
  130.   
  131.         private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;  
  132.         private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;  
  133.         private String redirectParameter = SPRING_SECURITY_FORM_REDERICT_KEY;  
  134.         private boolean postOnly = true;  
  135.   
  136.         //~ Constructors ===================================================================================================  
  137.   
  138.         public MyUsernamePasswordAuthenticationFilter() {  
  139.            super();  
  140.         }  
  141.   
  142.         //~ Methods ========================================================================================================  
  143.   
  144.         public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {  
  145.             if (postOnly && !request.getMethod().equals("POST")) {  
  146.                 throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());  
  147.             }  
  148.             String username = obtainUsername(request);  
  149.             String password = obtainPassword(request);  
  150.             String redirectUrl = obtainRedercitUrl(request);  
  151.             if (username == null) {  
  152.                 username = "";  
  153.             }  
  154.   
  155.             if (password == null) {  
  156.                 password = "";  
  157.             }  
  158.             //自定义回调URL,若存在则放入Session  
  159.             if(redirectUrl != null && !"".equals(redirectUrl)){  
  160.                 request.getSession().setAttribute("callCustomRediretUrl", redirectUrl);  
  161.             }  
  162.             username = username.trim();  
  163.             UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);  
  164.             // Allow subclasses to set the "details" property  
  165.             setDetails(request, authRequest);  
  166.             return this.getAuthenticationManager().authenticate(authRequest);  
  167.         }  
  168.   
  169.         /** 
  170.          * Enables subclasses to override the composition of the password, such as by including additional values 
  171.          * and a separator.<p>This might be used for example if a postcode/zipcode was required in addition to the 
  172.          * password. A delimiter such as a pipe (|) should be used to separate the password and extended value(s). The 
  173.          * <code>AuthenticationDao</code> will need to generate the expected password in a corresponding manner.</p> 
  174.          * 
  175.          * @param request so that request attributes can be retrieved 
  176.          * 
  177.          * @return the password that will be presented in the <code>Authentication</code> request token to the 
  178.          *         <code>AuthenticationManager</code> 
  179.          */  
  180.         protected String obtainPassword(HttpServletRequest request) {  
  181.             return request.getParameter(passwordParameter);  
  182.         }  
  183.   
  184.         /** 
  185.          * Enables subclasses to override the composition of the username, such as by including additional values 
  186.          * and a separator. 
  187.          * 
  188.          * @param request so that request attributes can be retrieved 
  189.          * 
  190.          * @return the username that will be presented in the <code>Authentication</code> request token to the 
  191.          *         <code>AuthenticationManager</code> 
  192.          */  
  193.         protected String obtainUsername(HttpServletRequest request) {  
  194.             return request.getParameter(usernameParameter);  
  195.         }  
  196.           
  197.           
  198.         protected String obtainRedercitUrl(HttpServletRequest request) {  
  199.             return request.getParameter(redirectParameter);  
  200.         }  
  201.   
  202.         /** 
  203.          * Provided so that subclasses may configure what is put into the authentication request's details 
  204.          * property. 
  205.          * 
  206.          * @param request that an authentication request is being created for 
  207.          * @param authRequest the authentication request object that should have its details set 
  208.          */  
  209.         protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {  
  210.             authRequest.setDetails(authenticationDetailsSource.buildDetails(request));  
  211.         }  
  212.   
  213.         /** 
  214.          * Sets the parameter name which will be used to obtain the username from the login request. 
  215.          * 
  216.          * @param usernameParameter the parameter name. Defaults to "j_username". 
  217.          */  
  218.         public void setUsernameParameter(String usernameParameter) {  
  219.             Assert.hasText(usernameParameter, "Username parameter must not be empty or null");  
  220.             this.usernameParameter = usernameParameter;  
  221.         }  
  222.   
  223.         /** 
  224.          * Sets the parameter name which will be used to obtain the password from the login request.. 
  225.          * 
  226.          * @param passwordParameter the parameter name. Defaults to "j_password". 
  227.          */  
  228.         public void setPasswordParameter(String passwordParameter) {  
  229.             Assert.hasText(passwordParameter, "Password parameter must not be empty or null");  
  230.             this.passwordParameter = passwordParameter;  
  231.         }  
  232.   
  233.         /** 
  234.          * Defines whether only HTTP POST requests will be allowed by this filter. 
  235.          * If set to true, and an authentication request is received which is not a POST request, an exception will 
  236.          * be raised immediately and authentication will not be attempted. The <tt>unsuccessfulAuthentication()</tt> method 
  237.          * will be called as if handling a failed authentication. 
  238.          * <p> 
  239.          * Defaults to <tt>true</tt> but may be overridden by subclasses. 
  240.          */  
  241.         public void setPostOnly(boolean postOnly) {  
  242.             this.postOnly = postOnly;  
  243.         }  
  244.   
  245.       
  246. }  
  247.   
  248.   
  249.   
  250. 4 SimpleUrlAuthenticationSuccessHandler重写  
  251.      public class MySavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler{  
  252.      @Value(value = "${local.service.url}")  
  253.      private String LOCAL_SERVER_URL;  
  254.       
  255.      protected final Log logger = LogFactory.getLog(this.getClass());  
  256.   
  257.         private RequestCache requestCache = new HttpSessionRequestCache();  
  258.   
  259.         @Override  
  260.         public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,  
  261.                 Authentication authentication) throws ServletException, IOException {  
  262.             SavedRequest savedRequest = requestCache.getRequest(request, response);  
  263.             if (savedRequest == null) {  
  264.                 System.out.println("savedRequest is null ");  
  265.                 //用户判断是否要使用上次通过session里缓存的回调URL地址  
  266.                 int flag = 0;  
  267.                 //通过提交登录请求传递需要回调的URL callCustomRediretUrl  
  268.                 if(request.getSession().getAttribute("callCustomRediretUrl") != null && !"".equals(request.getSession().getAttribute("callCustomRediretUrl"))){  
  269.                     String url = String.valueOf(request.getSession().getAttribute("callCustomRediretUrl"));  
  270.                     //若session 存在则需要使用自定义回调的URL 而不是缓存的URL  
  271.                     super.setDefaultTargetUrl(url);  
  272.                     super.setAlwaysUseDefaultTargetUrl(true);  
  273.                     flag = 1;  
  274.                     request.getSession().setAttribute("callCustomRediretUrl", "");  
  275.                 }  
  276.                 //重设置默认URL为主页地址  
  277.                 if(flag  == 0){  
  278.                     super.setDefaultTargetUrl(LOCAL_SERVER_URL);  
  279.                 }  
  280.                 super.onAuthenticationSuccess(request, response, authentication);  
  281.                  
  282.                 return;  
  283.             }  
  284.             //targetUrlParameter 是否存在  
  285.             String targetUrlParameter = getTargetUrlParameter();  
  286.             if (isAlwaysUseDefaultTargetUrl() || (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {  
  287.                 requestCache.removeRequest(request, response);  
  288.                 super.setAlwaysUseDefaultTargetUrl(false);  
  289.                 super.setDefaultTargetUrl("/");  
  290.                 super.onAuthenticationSuccess(request, response, authentication);  
  291.                 return;  
  292.             }  
  293.             //清除属性  
  294.             clearAuthenticationAttributes(request);  
  295.             // Use the DefaultSavedRequest URL  
  296.             String targetUrl = savedRequest.getRedirectUrl();  
  297.             logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);  
  298.             if(targetUrl != null && "".equals(targetUrl)){  
  299.                 targetUrl = LOCAL_SERVER_URL;  
  300.             }  
  301.             getRedirectStrategy().sendRedirect(request, response, targetUrl);  
  302.         }  
  303.   
  304.         public void setRequestCache(RequestCache requestCache) {  
  305.             this.requestCache = requestCache;  
  306.         }  
  307. }  
  308.   
  309. 5 认证失败控制类重写  
  310. /** 
  311.  * <tt>AuthenticationFailureHandler</tt> which performs a redirect to the value of the {@link #setDefaultFailureUrl 
  312.  * defaultFailureUrl} property when the <tt>onAuthenticationFailure</tt> method is called. 
  313.  * If the property has not been set it will send a 401 response to the client, with the error message from the 
  314.  * <tt>AuthenticationException</tt> which caused the failure. 
  315.  * <p> 
  316.  * If the {@code useForward} property is set, a {@code RequestDispatcher.forward} call will be made to 
  317.  * the destination instead of a redirect. 
  318.  * 
  319.  * @author Luke Taylor 
  320.  * @since 3.0 
  321.  */  
  322. public class MySimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler{  
  323.   
  324.     protected final Log logger = LogFactory.getLog(getClass());  
  325.   
  326.     private String defaultFailureUrl;  
  327.     private boolean forwardToDestination = false;  
  328.     private boolean allowSessionCreation = true;  
  329.     private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();  
  330.     @Value(value = "${local.service.url}")  
  331.     private String LOCAL_SERVER_URL;  
  332.       
  333.     public MySimpleUrlAuthenticationFailureHandler() {  
  334.     }  
  335.   
  336.     public MySimpleUrlAuthenticationFailureHandler(String defaultFailureUrl) {  
  337.         setDefaultFailureUrl(defaultFailureUrl);  
  338.     }  
  339.   
  340.     /** 
  341.      * Performs the redirect or forward to the {@code defaultFailureUrl} if set, otherwise returns a 401 error code. 
  342.      * <p> 
  343.      * If redirecting or forwarding, {@code saveException} will be called to cache the exception for use in 
  344.      * the target view. 
  345.      */  
  346.     public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,  
  347.             AuthenticationException exception) throws IOException, ServletException {  
  348.         //认证失败区别前后台:LOGIN URL  
  349.         if(request.getParameter("spring-security-redirect") != null){  
  350.               request.getSession().setAttribute("callUrlFailure", request.getParameter("spring-security-redirect"));  
  351.         }  
  352.         //若有loginUrl 则重定向到后台登录界面  
  353.         if(request.getParameter("loginUrl") != null && !"".equals(request.getParameter("loginUrl"))){  
  354.             defaultFailureUrl = LOCAL_SERVER_URL+"/backlogin.html?validated=false";  
  355.         }  
  356.         //defaultFailureUrl 默认的认证失败回调URL  
  357.         if (defaultFailureUrl == null) {  
  358.             logger.debug("No failure URL set, sending 401 Unauthorized error");  
  359.             response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage());  
  360.         } else {  
  361.             saveException(request, exception);  
  362.             if (forwardToDestination) {  
  363.                 logger.debug("Forwarding to " + defaultFailureUrl);  
  364.                 request.getRequestDispatcher(defaultFailureUrl).forward(request, response);  
  365.             } else {  
  366.                 logger.debug("Redirecting to " + defaultFailureUrl);  
  367.                 redirectStrategy.sendRedirect(request, response, defaultFailureUrl);  
  368.             }  
  369.         }  
  370.     }  
  371.   
  372.     /** 
  373.      * Caches the {@code AuthenticationException} for use in view rendering. 
  374.      * <p> 
  375.      * If {@code forwardToDestination} is set to true, request scope will be used, otherwise it will attempt to store 
  376.      * the exception in the session. If there is no session and {@code allowSessionCreation} is {@code true} a session 
  377.      * will be created. Otherwise the exception will not be stored. 
  378.      */  
  379.     protected final void saveException(HttpServletRequest request, AuthenticationException exception) {  
  380.         if (forwardToDestination) {  
  381.             request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);  
  382.         } else {  
  383.             HttpSession session = request.getSession(false);  
  384.   
  385.             if (session != null || allowSessionCreation) {  
  386.                 request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);  
  387.             }  
  388.         }  
  389.     }  
  390.   
  391.     /** 
  392.      * The URL which will be used as the failure destination. 
  393.      * 
  394.      * @param defaultFailureUrl the failure URL, for example "/loginFailed.jsp". 
  395.      */  
  396.     public void setDefaultFailureUrl(String defaultFailureUrl) {  
  397.         this.defaultFailureUrl = defaultFailureUrl;  
  398.     }  
  399.   
  400.     protected boolean isUseForward() {  
  401.         return forwardToDestination;  
  402.     }  
  403.   
  404.     /** 
  405.      * If set to <tt>true</tt>, performs a forward to the failure destination URL instead of a redirect. Defaults to 
  406.      * <tt>false</tt>. 
  407.      */  
  408.     public void setUseForward(boolean forwardToDestination) {  
  409.         this.forwardToDestination = forwardToDestination;  
  410.     }  
  411.   
  412.     /** 
  413.      * Allows overriding of the behaviour when redirecting to a target URL. 
  414.      */  
  415.     public void setRedirectStrategy(RedirectStrategy redirectStrategy) {  
  416.         this.redirectStrategy = redirectStrategy;  
  417.     }  
  418.   
  419.     protected RedirectStrategy getRedirectStrategy() {  
  420.         return redirectStrategy;  
  421.     }  
  422.   
  423.     protected boolean isAllowSessionCreation() {  
  424.         return allowSessionCreation;  
  425.     }  
  426.   
  427.     public void setAllowSessionCreation(boolean allowSessionCreation) {  
  428.         this.allowSessionCreation = allowSessionCreation;  
  429.     }  
  430.   
  431. }  
原文地址:https://www.cnblogs.com/lexiaofei/p/7018818.html