Spring Security 自定义登录验证与自定义回调地址

来源:互联网 发布:厨具收纳 知乎 编辑:程序博客网 时间:2024/04/29 19:30
1 配置文件 security-ns.xml        <?xml version="1.0" encoding="UTF-8"?>    <beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">    //需要过滤不被拦截的请求    <security:http pattern="/openapi/**" security="none" />    <security:http pattern="/useraccounts/userprofile.json" security="none" />    <security:http pattern="/useraccounts/register**" security="none" />        //entry-point-ref 配置自定义登录    <security:http auto-config="false" entry-point-ref="authenticationEntryPoint">        <security:intercept-url pattern="/backManage/**" access="ROLE_BACK_USER" />        <security:intercept-url pattern="/mall/**"       access="ROLE_BACK_USER" />        <security:intercept-url pattern="/thirdUser/**"  access="ROLE_USER" />        <security:intercept-url pattern="/useraccounts/**" access="ROLE_USER" />        <security:intercept-url pattern="/cart/**.html" access="ROLE_USER" />        <security:intercept-url pattern="/ticket/**" access="ROLE_USER,ROLE_BACK_USER" />        <security:intercept-url pattern="/order/**" access="ROLE_USER" />        <security:intercept-url pattern="/comment/**" access="ROLE_USER" />        <security:intercept-url pattern="/personal/**" access="ROLE_USER" />        <security:intercept-url pattern="/favorite/**" access="ROLE_USER" />            //需要替换的Filter顺序,配置自定义custom-filter时必须蔣auto-config="false",不然会报已经存在同样的过滤器错误        <security:custom-filter ref="myLoginFilter"  position="FORM_LOGIN_FILTER" />        //登出配置        <security:logout logout-success-url="${local.service.url}"/>    </security:http>     //密码加密工具类    <bean id="encoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>    //认证管理器    <security:authentication-manager alias="authenticationManager">        //UserDetailsService实现 主要用于用户的查询        <security:authentication-provider user-service-ref="userLoginService">            <security:password-encoder  ref="encoder">            </security:password-encoder>        </security:authentication-provider>    </security:authentication-manager>    <bean id="myLoginFilter" class="com.sale114.www.sercurity.MyUsernamePasswordAuthenticationFilter">        <property name="authenticationManager" ref="authenticationManager"/>        <property name="authenticationFailureHandler" ref="failureHandler"/>        <property name="authenticationSuccessHandler" ref="successHandler"/>    </bean>    //成功登录后    <bean id="successHandler" class="com.sale114.www.sercurity.MySavedRequestAwareAuthenticationSuccessHandler">        <property name="defaultTargetUrl" value="${local.service.url}"/>    </bean>    //登录失败    <bean id="failureHandler" class="com.sale114.www.sercurity.MySimpleUrlAuthenticationFailureHandler">        <property name="defaultFailureUrl" value="${local.service.url}/login.html?validated=false"/>    </bean>        <bean id="authenticationEntryPoint"        class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">        <property name="loginFormUrl" value="${local.service.url}/login.html" />    </bean></beans>2 UserLoginServiceImpl 查询用户实现类     @Named("userLoginService")public class UserLoginServiceImpl  implements UserDetailsService ,LoginService{    @Inject    private UserLoginDAO userLoginDAO;        @Override    public WrappedUserLogin getUserLogin() {        try {            WrappedUserLogin wrappedUserLogin = (WrappedUserLogin) SecurityContextHolder                    .getContext().getAuthentication().getPrincipal();            return wrappedUserLogin;        } catch (Exception e) {            return null;        }    }    @Override    public UserDetails loadUserByUsername(String username)            throws UsernameNotFoundException {        System.out.println("用户名-------------"+username);        UserLogin userLogin =  null;        if(username != null && !"".equals(username)&& username.indexOf("@") > 0){              userLogin = userLoginDAO.findByEmail(username);              username = userLogin.getNick();        }else{            userLogin = userLoginDAO.findByNick(username);        }        System.out.println("user is null ---"+userLogin.getUserType());        String nick = userLogin.getNick();        String email = userLogin.getEmail();        String mobile = userLogin.getMobile();        int userType = userLogin.getUserType();        List<GrantedAuthority> resultAuths = new ArrayList<GrantedAuthority>();                // 前台用户        if (userType == 1) {            resultAuths.add(new SimpleGrantedAuthority("ROLE_USER"));        } else {            resultAuths.add(new SimpleGrantedAuthority("ROLE_BACK_USER"));        }                return new WrappedUserLogin(userLogin.getId(), email, nick, mobile, userLogin.getPassword(), userType,resultAuths);    }}3 重写用户名密码验证     public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{        //用户名        public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";        //密码        public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";        //需要回调的URL 自定义参数        public static final String SPRING_SECURITY_FORM_REDERICT_KEY = "spring-security-redirect";                /**         * @deprecated If you want to retain the username, cache it in a customized {@code AuthenticationFailureHandler}         */        @Deprecated        public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";        private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;        private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;        private String redirectParameter = SPRING_SECURITY_FORM_REDERICT_KEY;        private boolean postOnly = true;        //~ Constructors ===================================================================================================        public MyUsernamePasswordAuthenticationFilter() {           super();        }        //~ Methods ========================================================================================================        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {            if (postOnly && !request.getMethod().equals("POST")) {                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());            }            String username = obtainUsername(request);            String password = obtainPassword(request);            String redirectUrl = obtainRedercitUrl(request);            if (username == null) {                username = "";            }            if (password == null) {                password = "";            }            //自定义回调URL,若存在则放入Session            if(redirectUrl != null && !"".equals(redirectUrl)){                request.getSession().setAttribute("callCustomRediretUrl", redirectUrl);            }            username = username.trim();            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);            // Allow subclasses to set the "details" property            setDetails(request, authRequest);            return this.getAuthenticationManager().authenticate(authRequest);        }        /**         * Enables subclasses to override the composition of the password, such as by including additional values         * and a separator.<p>This might be used for example if a postcode/zipcode was required in addition to the         * password. A delimiter such as a pipe (|) should be used to separate the password and extended value(s). The         * <code>AuthenticationDao</code> will need to generate the expected password in a corresponding manner.</p>         *         * @param request so that request attributes can be retrieved         *         * @return the password that will be presented in the <code>Authentication</code> request token to the         *         <code>AuthenticationManager</code>         */        protected String obtainPassword(HttpServletRequest request) {            return request.getParameter(passwordParameter);        }        /**         * Enables subclasses to override the composition of the username, such as by including additional values         * and a separator.         *         * @param request so that request attributes can be retrieved         *         * @return the username that will be presented in the <code>Authentication</code> request token to the         *         <code>AuthenticationManager</code>         */        protected String obtainUsername(HttpServletRequest request) {            return request.getParameter(usernameParameter);        }                        protected String obtainRedercitUrl(HttpServletRequest request) {            return request.getParameter(redirectParameter);        }        /**         * Provided so that subclasses may configure what is put into the authentication request's details         * property.         *         * @param request that an authentication request is being created for         * @param authRequest the authentication request object that should have its details set         */        protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {            authRequest.setDetails(authenticationDetailsSource.buildDetails(request));        }        /**         * Sets the parameter name which will be used to obtain the username from the login request.         *         * @param usernameParameter the parameter name. Defaults to "j_username".         */        public void setUsernameParameter(String usernameParameter) {            Assert.hasText(usernameParameter, "Username parameter must not be empty or null");            this.usernameParameter = usernameParameter;        }        /**         * Sets the parameter name which will be used to obtain the password from the login request..         *         * @param passwordParameter the parameter name. Defaults to "j_password".         */        public void setPasswordParameter(String passwordParameter) {            Assert.hasText(passwordParameter, "Password parameter must not be empty or null");            this.passwordParameter = passwordParameter;        }        /**         * Defines whether only HTTP POST requests will be allowed by this filter.         * If set to true, and an authentication request is received which is not a POST request, an exception will         * be raised immediately and authentication will not be attempted. The <tt>unsuccessfulAuthentication()</tt> method         * will be called as if handling a failed authentication.         * <p>         * Defaults to <tt>true</tt> but may be overridden by subclasses.         */        public void setPostOnly(boolean postOnly) {            this.postOnly = postOnly;        }    }4 SimpleUrlAuthenticationSuccessHandler重写     public class MySavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler{     @Value(value = "${local.service.url}")     private String LOCAL_SERVER_URL;         protected final Log logger = LogFactory.getLog(this.getClass());        private RequestCache requestCache = new HttpSessionRequestCache();        @Override        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,                Authentication authentication) throws ServletException, IOException {            SavedRequest savedRequest = requestCache.getRequest(request, response);            if (savedRequest == null) {                System.out.println("savedRequest is null ");                //用户判断是否要使用上次通过session里缓存的回调URL地址                int flag = 0;                //通过提交登录请求传递需要回调的URL callCustomRediretUrl                if(request.getSession().getAttribute("callCustomRediretUrl") != null && !"".equals(request.getSession().getAttribute("callCustomRediretUrl"))){                    String url = String.valueOf(request.getSession().getAttribute("callCustomRediretUrl"));                    //若session 存在则需要使用自定义回调的URL 而不是缓存的URL                    super.setDefaultTargetUrl(url);                    super.setAlwaysUseDefaultTargetUrl(true);                    flag = 1;                    request.getSession().setAttribute("callCustomRediretUrl", "");                }                //重设置默认URL为主页地址                if(flag  == 0){                    super.setDefaultTargetUrl(LOCAL_SERVER_URL);                }                super.onAuthenticationSuccess(request, response, authentication);                               return;            }            //targetUrlParameter 是否存在            String targetUrlParameter = getTargetUrlParameter();            if (isAlwaysUseDefaultTargetUrl() || (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {                requestCache.removeRequest(request, response);                super.setAlwaysUseDefaultTargetUrl(false);                super.setDefaultTargetUrl("/");                super.onAuthenticationSuccess(request, response, authentication);                return;            }            //清除属性            clearAuthenticationAttributes(request);            // Use the DefaultSavedRequest URL            String targetUrl = savedRequest.getRedirectUrl();            logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);            if(targetUrl != null && "".equals(targetUrl)){                targetUrl = LOCAL_SERVER_URL;            }            getRedirectStrategy().sendRedirect(request, response, targetUrl);        }        public void setRequestCache(RequestCache requestCache) {            this.requestCache = requestCache;        }}5 认证失败控制类重写/** * <tt>AuthenticationFailureHandler</tt> which performs a redirect to the value of the {@link #setDefaultFailureUrl * defaultFailureUrl} property when the <tt>onAuthenticationFailure</tt> method is called. * If the property has not been set it will send a 401 response to the client, with the error message from the * <tt>AuthenticationException</tt> which caused the failure. * <p> * If the {@code useForward} property is set, a {@code RequestDispatcher.forward} call will be made to * the destination instead of a redirect. * * @author Luke Taylor * @since 3.0 */public class MySimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler{    protected final Log logger = LogFactory.getLog(getClass());    private String defaultFailureUrl;    private boolean forwardToDestination = false;    private boolean allowSessionCreation = true;    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();    @Value(value = "${local.service.url}")    private String LOCAL_SERVER_URL;        public MySimpleUrlAuthenticationFailureHandler() {    }    public MySimpleUrlAuthenticationFailureHandler(String defaultFailureUrl) {        setDefaultFailureUrl(defaultFailureUrl);    }    /**     * Performs the redirect or forward to the {@code defaultFailureUrl} if set, otherwise returns a 401 error code.     * <p>     * If redirecting or forwarding, {@code saveException} will be called to cache the exception for use in     * the target view.     */    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,            AuthenticationException exception) throws IOException, ServletException {        //认证失败区别前后台:LOGIN URL        if(request.getParameter("spring-security-redirect") != null){              request.getSession().setAttribute("callUrlFailure", request.getParameter("spring-security-redirect"));        }        //若有loginUrl 则重定向到后台登录界面        if(request.getParameter("loginUrl") != null && !"".equals(request.getParameter("loginUrl"))){            defaultFailureUrl = LOCAL_SERVER_URL+"/backlogin.html?validated=false";        }        //defaultFailureUrl 默认的认证失败回调URL        if (defaultFailureUrl == null) {            logger.debug("No failure URL set, sending 401 Unauthorized error");            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage());        } else {            saveException(request, exception);            if (forwardToDestination) {                logger.debug("Forwarding to " + defaultFailureUrl);                request.getRequestDispatcher(defaultFailureUrl).forward(request, response);            } else {                logger.debug("Redirecting to " + defaultFailureUrl);                redirectStrategy.sendRedirect(request, response, defaultFailureUrl);            }        }    }    /**     * Caches the {@code AuthenticationException} for use in view rendering.     * <p>     * If {@code forwardToDestination} is set to true, request scope will be used, otherwise it will attempt to store     * the exception in the session. If there is no session and {@code allowSessionCreation} is {@code true} a session     * will be created. Otherwise the exception will not be stored.     */    protected final void saveException(HttpServletRequest request, AuthenticationException exception) {        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);            }        }    }    /**     * The URL which will be used as the failure destination.     *     * @param defaultFailureUrl the failure URL, for example "/loginFailed.jsp".     */    public void setDefaultFailureUrl(String defaultFailureUrl) {        this.defaultFailureUrl = defaultFailureUrl;    }    protected boolean isUseForward() {        return forwardToDestination;    }    /**     * If set to <tt>true</tt>, performs a forward to the failure destination URL instead of a redirect. Defaults to     * <tt>false</tt>.     */    public void setUseForward(boolean forwardToDestination) {        this.forwardToDestination = forwardToDestination;    }    /**     * Allows overriding of the behaviour when redirecting to a target URL.     */    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {        this.redirectStrategy = redirectStrategy;    }    protected RedirectStrategy getRedirectStrategy() {        return redirectStrategy;    }    protected boolean isAllowSessionCreation() {        return allowSessionCreation;    }    public void setAllowSessionCreation(boolean allowSessionCreation) {        this.allowSessionCreation = allowSessionCreation;    }}     6 登录Controller和页面省略


0 0
原创粉丝点击