SpringSecurity自定义过滤器之后Session会话控制失效!!求大神指点

Clumsy_Bird 2014-09-28 10:06:21
最近在研究SpringSecurity开始一切正常但是自定义过滤器后却发现对Session控制的会话控制失效了。网上说如果重写了User类要重写equals和hashCode方法。但是我没有重写User类也不好使,之后我重写了后也重写了equals和hashCode方法,还是不好使。调试之后根本没有进入equals方法但是hashCode方法却走了很多遍。求大神指点。下面开帖代码。
applicationContext-security.xml代码

<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">

<!-- 访问被拒绝时跳转到403界面 -->
<http entry-point-ref="authenticationProcessingFilterEntryPoint"
access-denied-page="/403.jsp" >
<!-- 放行页面 -->
<intercept-url pattern="/*.css" filters="none" />
<intercept-url pattern="/error.jsp" filters="none" />
<intercept-url pattern="/index*.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="any" />
<!-- 访问全部要通过身份验证 -->
<intercept-url pattern="/**" access="isAuthenticated()" />
<!-- 访问全部要有ROLE_USER权限 -->
<intercept-url pattern="/**" access="ROLE_USER" />

<!-- 安全退出后的页面 -->
<logout logout-success-url="/logout.jsp" />
<!-- 两周内记住我 -->
<remember-me key="jbcpPetStore" />

<!-- 检测失效的sessionId,超时时定位到另外一个URL, -->
<session-management
session-authentication-error-url="/No_certification.jsp"
invalid-session-url="/index.jsp" session-fixation-protection="migrateSession">
<!-- 防止多端登录 -->
<concurrency-control max-sessions="1"
error-if-maximum-exceeded="true" expired-url="/error.jsp" />
</session-management>

<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER" />
</http>

<!-- 自定义登录过滤 -->
<beans:bean id="loginFilter"
class="filter.UsernamePasswordAuthenticationExtendFilter">
<!-- 验证页面 -->
<beans:property name="filterProcessesUrl" value="/j_spring_security_check" />
<!-- 验证成功后的处理 -->
<beans:property name="authenticationSuccessHandler"
ref="loginLogAuthenticationSuccessHandler" />
<!-- 验证失败后的处理 -->
<beans:property name="authenticationFailureHandler"
ref="simpleUrlAuthenticationFailureHandler" />
<!-- 认证器 -->
<beans:property name="authenticationManager" ref="authenticationManager" />

</beans:bean>

<!-- 认证器 -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref='myUserDetailsService' />
</authentication-manager>

<!-- 注入认证器 -->
<beans:bean id="myUserDetailsService" class="filter.MyUserDetailService" />

<!-- 开始注入登录过滤器 -->
<beans:bean id="loginLogAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/welcome.jsp"></beans:property>
</beans:bean>
<beans:bean id="simpleUrlAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/index.jsp?error=true"></beans:property>
</beans:bean>
<!-- 注入登录过滤器结束 -->

<beans:bean id="authenticationProcessingFilterEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/index.jsp"></beans:property>
</beans:bean>

</beans:beans>

web.xml页面

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 防止请求Spring乱码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<!--强制转换编码(request和response均适用) -->
<param-name>ForceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring Security过滤器 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Struts2 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<!-- Spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml,classpath:applicationContext-security.xml</param-value>
</context-param>
<!-- Spring监听 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 监听session 防止多端登录 -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<!-- session有效期为30分 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>

...全文
3115 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
平凡人001 2017-01-17
  • 打赏
  • 举报
回复
引用 12 楼 lxw7552 的回复:
这个我已经解决了,我的配置是注解方式。是因为你只加了UsernamePasswordAuthenticationExtendFilter,但是他的AuthenticationProvider还是springsecurity默认的,你需要自定义,所以你加的UsernamePasswordAuthenticationExtendFilter是不能正常工作的,还需要覆盖他默认的DaoAuthenticationProvider后,修改HttpSecurity,然后获取HttpSecurity的AuthenticationManager,将获取的AuthenticationManager交给你加的UsernamePasswordAuthenticationExtendFilter。 代码的主要部分:

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	@Qualifier(value = "userDetailsService")
	private UserDetailsService userDetailsService;
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 覆盖 UsernamePasswordAuthenticationFilter
		http.addFilterAt(usernamePasswordAuthenticationFilterWrapper(), UsernamePasswordAuthenticationFilter.class);
		http.authenticationProvider(daoAuthenticationProviderWrapper());
}
public DaoAuthenticationProviderWrapper daoAuthenticationProviderWrapper() {
		DaoAuthenticationProviderWrapper daoAuthenticationProviderWrapper = new DaoAuthenticationProviderWrapper();
		daoAuthenticationProviderWrapper.setUserDetailsService(userDetailsService);
		// 指定密码加密所使用的加密器为passwordEncoder()
		// daoAuthenticationProviderWrapper.setPasswordEncoder(passwordEncoder());
		return daoAuthenticationProviderWrapper;
	}

public UsernamePasswordAuthenticationFilterWrapper usernamePasswordAuthenticationFilterWrapper() {
		UsernamePasswordAuthenticationFilterWrapper usernamePasswordAuthenticationFilterWrapper = new UsernamePasswordAuthenticationFilterWrapper();
		try {
			usernamePasswordAuthenticationFilterWrapper.setAuthenticationManager(authenticationManagerBean());
		} catch (Exception e) {
			logger.error(
					"WebSecurityConfig.usernamePasswordAuthenticationFilterWrapper, init UsernamePasswordAuthenticationFilterWrapper error: {}",
					e);
		}
		return usernamePasswordAuthenticationFilterWrapper;
	}

	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}
}
这个应该怎么整合到项目里,求指点
lxw7552 2016-08-05
  • 打赏
  • 举报
回复
这个我已经解决了,我的配置是注解方式。是因为你只加了UsernamePasswordAuthenticationExtendFilter,但是他的AuthenticationProvider还是springsecurity默认的,你需要自定义,所以你加的UsernamePasswordAuthenticationExtendFilter是不能正常工作的,还需要覆盖他默认的DaoAuthenticationProvider后,修改HttpSecurity,然后获取HttpSecurity的AuthenticationManager,将获取的AuthenticationManager交给你加的UsernamePasswordAuthenticationExtendFilter。 代码的主要部分:

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	@Qualifier(value = "userDetailsService")
	private UserDetailsService userDetailsService;
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 覆盖 UsernamePasswordAuthenticationFilter
		http.addFilterAt(usernamePasswordAuthenticationFilterWrapper(), UsernamePasswordAuthenticationFilter.class);
		http.authenticationProvider(daoAuthenticationProviderWrapper());
}
public DaoAuthenticationProviderWrapper daoAuthenticationProviderWrapper() {
		DaoAuthenticationProviderWrapper daoAuthenticationProviderWrapper = new DaoAuthenticationProviderWrapper();
		daoAuthenticationProviderWrapper.setUserDetailsService(userDetailsService);
		// 指定密码加密所使用的加密器为passwordEncoder()
		// daoAuthenticationProviderWrapper.setPasswordEncoder(passwordEncoder());
		return daoAuthenticationProviderWrapper;
	}

public UsernamePasswordAuthenticationFilterWrapper usernamePasswordAuthenticationFilterWrapper() {
		UsernamePasswordAuthenticationFilterWrapper usernamePasswordAuthenticationFilterWrapper = new UsernamePasswordAuthenticationFilterWrapper();
		try {
			usernamePasswordAuthenticationFilterWrapper.setAuthenticationManager(authenticationManagerBean());
		} catch (Exception e) {
			logger.error(
					"WebSecurityConfig.usernamePasswordAuthenticationFilterWrapper, init UsernamePasswordAuthenticationFilterWrapper error: {}",
					e);
		}
		return usernamePasswordAuthenticationFilterWrapper;
	}

	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}
}
洪河杰拉德 2016-04-13
  • 打赏
  • 举报
回复
指定了ConcurrentSessionControlAuthenticationStrategy,还是会出现同样的问题,下面附上源码,求求大神指点

<session-management session-authentication-strategy-ref="concurrentSessionControlAuthenticationStrategy"/>
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
    <beans:bean id="concurrentSessionControlAuthenticationStrategy" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
        <beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" />
        <beans:property name="maximumSessions" value="1" />
    </beans:bean>
洪河杰拉德 2016-04-13
  • 打赏
  • 举报
回复
楼主解决了吗?现在遇到同样的问题,求解决方案
Chenctrl 2015-11-21
  • 打赏
  • 举报
回复
因为你没有指定session策略啊,下面是源码:
public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
		implements ApplicationEventPublisherAware, MessageSourceAware {
	// ~ Static fields/initializers
	// =====================================================================================

	// ~ Instance fields
	// ================================================================================================

	protected ApplicationEventPublisher eventPublisher;
	protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
	private AuthenticationManager authenticationManager;
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private RememberMeServices rememberMeServices = new NullRememberMeServices();

	private RequestMatcher requiresAuthenticationRequestMatcher;

	private boolean continueChainBeforeSuccessfulAuthentication = false;

	private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
看最后一行,在配置文件里,弄成这样试试:
<beans:bean id="loginFilter"
		class="com.bay1ts.security.CustomUsernamePasswordAuthenticationFilter">
		<!-- 验证成功后的处理 -->
		<beans:property name="authenticationSuccessHandler"
			ref="loginLogAuthenticationSuccessHandler" />
		<!-- 验证失败后的处理 -->
		<beans:property name="authenticationFailureHandler"
			ref="simpleUrlAuthenticationFailureHandler" />
		<beans:property name="authenticationManager" ref="authenticationManager" />
		<beans:property name="sessionAuthenticationStrategy"
			ref="sas" />
		<beans:property name="rememberMeServices" ref="rememberMeServices" />
	</beans:bean>
情况不一样,我这是加了一个过滤器,原来的过滤器来留着呢,但是我发现原来的过滤器的session不好用了。。
baidu_30375421 2015-08-17
  • 打赏
  • 举报
回复
SessionAuthenticationStrategy 需指定为org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy
t_mac521 2015-04-14
  • 打赏
  • 举报
回复
遇到同样问题
Clumsy_Bird 2014-09-28
  • 打赏
  • 举报
回复
人工置顶!!!!
蜗牛_snail 2014-09-28
  • 打赏
  • 举报
回复
Clumsy_Bird 2014-09-28
  • 打赏
  • 举报
回复
自顶!!!!
Clumsy_Bird 2014-09-28
  • 打赏
  • 举报
回复
继承UsernamePasswordAuthenticationFilter类的代码

package filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
  

/** 
 * 重载SECURITY3的UsernamePasswordAuthenticationFilter的attemptAuthentication, 
 * obtainUsername,obtainPassword方法(完善逻辑) 增加验证码校验模块 添加验证码属性 添加验证码功能开关属性 
 *  
 * @author shadow 
 * @email 124010356@qq.com 
 * @create 2012.04.28 
 */
public class UsernamePasswordAuthenticationExtendFilter extends UsernamePasswordAuthenticationFilter  {
	
	private SessionAuthenticationStrategy  sessionAuthenticationStrategy = null;
	
	
	public SessionAuthenticationStrategy getSessionAuthenticationStrategy() {
		return sessionAuthenticationStrategy;
	}
	
	public void setSessionAuthenticationStrategy(
			SessionAuthenticationStrategy sessionAuthenticationStrategy) {
		this.sessionAuthenticationStrategy = sessionAuthenticationStrategy;
	}

		// 验证码字段
		private String validateCodeParameter = "validateCode";
		// 是否开启验证码功能
		private boolean openValidateCode = false;

		@Override
		public Authentication attemptAuthentication(HttpServletRequest request,
				HttpServletResponse response) throws AuthenticationException {
			request.getSession().removeAttribute("msg");
			// 只接受POST方式传递的数据
			if (!"POST".equals(request.getMethod())){
				throw new AuthenticationServiceException("不支持非POST方式的请求!");
			}

			// 开启验证码功能的情况
			if (isOpenValidateCode()){
				checkValidateCode(request);
			}

			// 获取Username和Password
			String username = obtainUsername(request);
			String password = obtainPassword(request);

			// UsernamePasswordAuthenticationToken实现Authentication校验
			UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
					username, password);

			// 允许子类设置详细属性
			setDetails(request, authRequest);

			// 运行UserDetailsService的loadUserByUsername 再次封装Authentication
			return this.getAuthenticationManager().authenticate(authRequest);
		}

		// 匹对验证码的正确性
		public void checkValidateCode(HttpServletRequest request) {
			String jcaptchaCode = obtainValidateCodeParameter(request);
			if (null == jcaptchaCode || "".equals(jcaptchaCode)){
				throw new AuthenticationServiceException("请输入验证码");    
			}
			if(null == request.getSession().getAttribute("rand")){
				throw new AuthenticationServiceException("验证码失效");    
			}
			//对比普通验证码
			if(!request.getSession().getAttribute("rand").equals(jcaptchaCode)){
				throw new AuthenticationServiceException("验证码错误!");    
			}
			return;
		}

		public String obtainValidateCodeParameter(HttpServletRequest request) {
			Object obj = request.getParameter(getValidateCodeParameter());
			return null == obj ? "" : obj.toString().trim();
		}

		@Override
		protected String obtainUsername(HttpServletRequest request) {
			Object obj = request.getParameter(getUsernameParameter());
			return null == obj ? "" : obj.toString().trim();
		}

		@Override
		protected String obtainPassword(HttpServletRequest request) {
			Object obj = request.getParameter(getPasswordParameter());
			return null == obj ? "" : obj.toString().trim();
		}

		public String getValidateCodeParameter() {
			return validateCodeParameter;
		}

		public void setValidateCodeParameter(String validateCodeParameter) {
			this.validateCodeParameter = validateCodeParameter;
		}

		public boolean isOpenValidateCode() {
			return openValidateCode;
		}

		public void setOpenValidateCode(boolean openValidateCode) {
			this.openValidateCode = openValidateCode;
		}
}

UserDetailsService页面代码

package filter;

import java.util.ArrayList;
import java.util.Collection;

import model.UserDetail;

import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

/**
 * 登录类
 * 
 * @author Administrator
 * @comment 在这个类中,你就可以从数据库中读入用户的密码、角色信息、是否锁定、 账号是否过期等. new User()方法参数说明, String
 *          username(用户名), String password(密码), boolean enabled(账户是否可用), boolean
 *          accountNonExpired(账户是否未过期), boolean accountNonLocked(账户是否未锁定),
 *          Collection<GrantedAuthority> authorities(账户所受权限).
 */
public class MyUserDetailService implements UserDetailsService {
	
	
	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException, DataAccessException {
		Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
		GrantedAuthorityImpl auth2 = new GrantedAuthorityImpl("ROLE_USER");// 进行授权
		auths.add(auth2);// 添加所授的权限 
		UserDetail user = new UserDetail("123", "123", true, true, true, true, auths);
		return  user;
	}
}
UserDetail类方法

package model;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@SuppressWarnings("serial")
public class UserDetail implements UserDetails {
	private Collection<GrantedAuthority> authorities;
	private String password;
	private String username;
	private boolean isAccountNonExpired;
	private boolean isAccountNonLocked;
	private boolean isCredentialsNonExpired;
	private boolean isEnabled;

	/** default constructor */
	public UserDetail() {
	}

	public UserDetail(String username, String password,
			boolean isAccountNonExpired, boolean isAccountNonLocked,
			boolean isCredentialsNonExpired, boolean isEnabled, Collection<GrantedAuthority> authorities) {
		this.username = username;
		this.password = password;
		this.isAccountNonExpired = isAccountNonExpired;
		this.isAccountNonLocked = isAccountNonLocked;
		this.isCredentialsNonExpired = isCredentialsNonExpired;
		this.isEnabled = isEnabled;
		this.authorities = authorities;
	}

	// Constructors

	public Collection<GrantedAuthority> getAuthorities() {
		return authorities;
	}

	public void setAuthorities(Collection<GrantedAuthority> authorities) {
		this.authorities = authorities;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public boolean isAccountNonExpired() {
		return isAccountNonExpired;
	}

	public void setAccountNonExpired(boolean isAccountNonExpired) {
		this.isAccountNonExpired = isAccountNonExpired;
	}

	public boolean isAccountNonLocked() {
		return isAccountNonLocked;
	}

	public void setAccountNonLocked(boolean isAccountNonLocked) {
		this.isAccountNonLocked = isAccountNonLocked;
	}

	public boolean isCredentialsNonExpired() {
		return isCredentialsNonExpired;
	}

	public void setCredentialsNonExpired(boolean isCredentialsNonExpired) {
		this.isCredentialsNonExpired = isCredentialsNonExpired;
	}

	public boolean isEnabled() {
		return isEnabled;
	}

	public void setEnabled(boolean isEnabled) {
		this.isEnabled = isEnabled;
	}
	
	@Override
	public boolean equals(Object obj) {
		System.out.println("进入equals方法");
		if (obj instanceof UserDetail) {
			UserDetail another = (UserDetail)obj;
			return this.getUsername().equals(another.getUsername());
		}
		return super.equals(obj);
	}

	@Override
	public int hashCode() {
		System.out.println("进入hashCode方法");
		return this.getUsername().hashCode();
	}
	
}

Clumsy_Bird 2014-09-28
  • 打赏
  • 举报
回复
人工置顶!!!!!!
Clumsy_Bird 2014-09-28
  • 打赏
  • 举报
回复
大神们呢?? 不要沉啊!!!!!

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧