spring security实现传参

来源:互联网 发布:网络的利与弊作文1000 编辑:程序博客网 时间:2024/05/21 11:08

      本人现在开发的项目中用到了spring security3.1.2来实现登陆验证,但默认的过滤器UsernamePasswordAuthenticationFilter只能传递两个参数j_username和j_password,如果要传递验证码或首次打开的页面URL参数,只能重写UsernamePasswordAuthenticationFilter。

     对于不了解spring security3.1的童鞋,请先阅读本人写的另一篇博客Spring Security权限管理,下面将在这篇博客的基础上,添加一个功能:传递登陆之前的页面URL。公司现在做的项目,如果没有登陆或会话超时,都要求重新登陆,登陆之后会直接跳转到首页,而不是跳转到原来打开的页面,这很恶心。于是本人决心对项目进行改造,使得可以传递最后打开页面的URL,登陆之后直接跳转到这个URL去。

1.重写UsernamePasswordAuthenticationFilter

package com.web.filter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;import org.springframework.util.Assert;/** * 验证登陆用户名和密码的拦截器,记录最后登陆页面 * @author brushli * @date 2014-10-30 */public class MyUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";    public static final String SPRING_SECURITY_FORM_LAST_LOGIN_URL_KEY = "lastLoginUrl";    public static final String SPRING_SECURITY_SPLIT = ",";    /**     * @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 lastLoginUrlParameter = SPRING_SECURITY_FORM_LAST_LOGIN_URL_KEY;    private String split = SPRING_SECURITY_SPLIT;    private boolean postOnly = true;    //~ Constructors ===================================================================================================    public MyUsernamePasswordAuthenticationFilter() {        super("/j_spring_security_check");    }    //~ 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 lastLoginUrl = obtainLastLoginUrl(request);        if (username == null) {            username = "";        }        if (password == null) {            password = "";        }                if (lastLoginUrl == null) {        lastLoginUrl = "";        }        username = username.trim();        username = username + SPRING_SECURITY_SPLIT + lastLoginUrl;        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 obtainLastLoginUrl(HttpServletRequest request) {        return request.getParameter(lastLoginUrlParameter);    }    /**     * 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;    }    public final String getUsernameParameter() {        return usernameParameter;    }    public final String getPasswordParameter() {        return passwordParameter;    }public String getLastLoginUrlParameter() {return lastLoginUrlParameter;}public void setLastLoginUrlParameter(String lastLoginUrlParameter) {Assert.hasText(lastLoginUrlParameter, "lastLoginUrl Parameter must not be empty or null");this.lastLoginUrlParameter = lastLoginUrlParameter;}public String getSplit() {return split;}/** * The string to separate username and lastLoginUrl  * @param split */public void setSplit(String split) {this.split = split;}}

2.修改AuthenticationFailHandlerImpl

package com.service.impl; import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.AuthenticationFailureHandler;import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;public class AuthenticationFailHandlerImpl extends SimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler {/** * 登录时密码或账号不正确时的操作 */@Overridepublic void onAuthenticationFailure(HttpServletRequest request,HttpServletResponse response, AuthenticationException exception)throws IOException, ServletException {String lastLoginUrl = request.getParameter("lastLoginUrl");if(lastLoginUrl == null){lastLoginUrl = "";}lastLoginUrl = lastLoginUrl.replace("?", "%3F");lastLoginUrl = lastLoginUrl.replace("&", "%26");logger.info("lastLoginUrl=" + lastLoginUrl);response.sendRedirect(request.getContextPath() + "/login.jsp?result=0&lastLoginUrl="+lastLoginUrl);return;}}

3.修改AuthenticationSuccessHandlerImpl

package com.service.impl;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.springframework.security.core.Authentication;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;import com.bean.UserLoginDetails;/** * Authentication Handler for redirect the original inputed URL after login system. */public class AuthenticationSuccessHandlerImpl extends SimpleUrlAuthenticationSuccessHandler implements AuthenticationSuccessHandler {/** * 登录时通过密码验证后进行的操作 */@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {//查询当前登录用户有权限的功能if(!SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser")){UserLoginDetails userDetails = (UserLoginDetails) authentication.getPrincipal();HttpSession session = request.getSession();session.setAttribute("userDetails", userDetails);logger.info("lastLoginUrl=" + userDetails.getLastLoginUrl());if(userDetails.getLastLoginUrl() != null && !"".equals(userDetails.getLastLoginUrl().trim())){response.sendRedirect(userDetails.getLastLoginUrl());}else{response.sendRedirect(request.getContextPath() + "/myPage/myPage.jsp");}}return;}}

4.修改WebUserDetailsService

package com.service.impl;import java.util.HashSet;import java.util.Set;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import com.bean.Role;import com.bean.User;import com.bean.UserLoginDetails;import com.service.UserService;import com.web.filter.MyUsernamePasswordAuthenticationFilter;/** * 用户登录是准备阶段的业务逻辑 */public class WebUserDetailsService implements UserDetailsService {protected static final Logger logger = LoggerFactory.getLogger(WebUserDetailsService.class);private UserService userService;public void setUserService(UserService userService) {this.userService = userService;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {boolean accountNonExpired = true;          boolean credentialsNonExpired = true;          boolean accountNonLocked = true;        boolean enabled = true;                String[] usernameLastLoginUrl = username.split(MyUsernamePasswordAuthenticationFilter.SPRING_SECURITY_SPLIT);String lastLoginUrl = "";if(usernameLastLoginUrl.length == 1){username = usernameLastLoginUrl[0];}else if(usernameLastLoginUrl.length == 2){username = usernameLastLoginUrl[0];lastLoginUrl = usernameLastLoginUrl[1];}        User user = null;        try {user = userService.getUserByUsername(username);} catch (Exception e) {e.printStackTrace();}                if(user == null){throw new UsernameNotFoundException("User account : " + username + " not found!");}                //封装该用户具有什么角色        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();         if(user.getRoles() != null && !user.getRoles().isEmpty()){        for(Role role : user.getRoles()){        GrantedAuthority ga = new SimpleGrantedAuthority(role.getName());        authorities.add(ga);               }        }                UserLoginDetails userLoginDetails =  new UserLoginDetails(user.getUsername(), user.getPassword(), authorities,         accountNonExpired, accountNonLocked, credentialsNonExpired, enabled, lastLoginUrl);        return userLoginDetails;}}

5.修改UserLoginDetails

package com.bean;import java.util.Collection;import java.util.Set;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;public class UserLoginDetails implements UserDetails {private static final long serialVersionUID = 1L;private String username;private String password;private Set<GrantedAuthority> authorities = null;private boolean accountNonExpired = false;//账号未过期    private boolean accountNonLocked = false;//账号未锁定    private boolean credentialsNonExpired = false;//证书未过期    private boolean enabled = false;//是否可用     private final String lastLoginUrl;//最后登陆的页面        public UserLoginDetails(String username, String password, Set<GrantedAuthority> authorities, boolean accountNonExpired,     boolean accountNonLocked, boolean credentialsNonExpired, boolean enabled, String lastLoginUrl){    this.username = username;    this.password = password;    this.authorities = authorities;    this.accountNonExpired = accountNonExpired;    this.accountNonLocked = accountNonLocked;    this.credentialsNonExpired = credentialsNonExpired;    this.enabled = enabled;    this.lastLoginUrl = lastLoginUrl;    }    public Collection<? extends GrantedAuthority> getAuthorities() {return authorities;}public String getPassword() {return password;}public String getUsername() {return username;}public boolean isAccountNonExpired() {return accountNonExpired;}public boolean isAccountNonLocked() {return accountNonLocked;}public boolean isCredentialsNonExpired() {return credentialsNonExpired;}public boolean isEnabled() {return enabled;}public String getLastLoginUrl() {return lastLoginUrl;}}

6.修改配置文件

<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/security"xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:context="http://www.springframework.org/schema/context"     xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsdhttp://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   http://www.springframework.org/schema/context    http://www.springframework.org/schema/context/spring-context-3.0.xsd"><!-- 访问login.jsp页面不需要权限验证  --><http pattern="/login.jsp" security="none"/><!-- This is where we configure Spring-Security  --><!-- <http auto-config="true" use-expressions="true"> --><http auto-config="false" use-expressions="true" access-denied-page="/deny.jsp" entry-point-ref="authenticationEntryPoint"><intercept-url pattern="/admin/**" access="hasRole('admin')"/><!-- 用户只有拥有角色admin才能访问/admin目录下面的资源 --><intercept-url pattern="/myPage/**"access="hasAnyRole('admin', 'myRole')"/><!-- 用户拥有角色admin,myRole中的任意一个就能访问/myPage目录下面的资源 --><!-- <form-loginlogin-page="/login.jsp"authentication-failure-url="/deny.jsp" default-target-url="/index.jsp" authentication-success-handler-ref="authenticationSuccessHandlerImpl"authentication-failure-handler-ref="authenticationFailHandlerImpl"/> --><!--     配置自定义的Filter,并且将其放在FORM_LOGIN_FILTER节点,就会替换掉原来的FORM_LOGIN_FILTER节点      设置auto-config="false",不然会报已经存在同样的过滤器错误,同时还要删除<form-login>   --><custom-filter ref="loginProcessFilter" position ="FORM_LOGIN_FILTER" /><logout invalidate-session="true" logout-success-url="/login.jsp" />         <!-- 增加一个自定义的filter,放在FILTER_SECURITY_INTERCEPTOR之前,  实现用户、角色、权限、资源的数据库管理。  -->          <custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR"/>        </http><beans:bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">  <beans:property name="loginFormUrl" value="/login.jsp"></beans:property>  </beans:bean><beans:bean id="loginProcessFilter" class="com.web.filter.MyUsernamePasswordAuthenticationFilter"><beans:property name="authenticationManager" ref="authenticationManagerService"></beans:property><beans:property name="authenticationSuccessHandler" ref="authenticationSuccessHandlerImpl"></beans:property><beans:property name="authenticationFailureHandler" ref="authenticationFailHandlerImpl"></beans:property></beans:bean><beans:bean id="securityFilter" class="com.filter.SecurityInterceptorFilter">  <beans:property name="authenticationManager" ref="authenticationManagerService"/>  <beans:property name="accessDecisionManager" ref="accessDecisionManagerService"/>  <beans:property name="securityMetadataSource" ref="securityMetadataSourceService"/>  </beans:bean><beans:bean id="securityMetadataSourceService" class="com.service.impl.SecurityMetadataSourceService" init-method="loadAllResources">    <beans:property name="userService" ref="userService"/></beans:bean><!-- Declare an authentication-manager to use a custom userDetailsService --><authentication-manager alias="authenticationManagerService"><authentication-provider user-service-ref="webUserDetailsService">    <password-encoder hash="md5" /></authentication-provider></authentication-manager><beans:bean id="accessDecisionManagerService" class="com.service.impl.AccessDecisionManagerService" /> </beans:beans>

7.程序运行结果

我们打开首页:http://localhost:8082/springSecurity/index.jsp

程序会自动跳转到登陆页面:http://localhost:8082/springSecurity/login.jsp?lastLoginUrl=/springSecurity/index.jsp

后面会附带首页的URL,输入正确的用户名和密码后,就会自动跳转到首页

7.项目的代码结构

8.项目源代码下载

包括整个项目的源代码和MYSQL建库脚本

http://download.csdn.net/detail/brushli/7865697

 

0 0
原创粉丝点击