spring session+spring security 实现用户不能重复登录

本文介绍如何在Spring Security中配置Spring Session以实现session共享,并解决了在集群环境下可能出现的SessionFixation问题及并发会话管理。同时给出了具体的登录和登出代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring session 是为了session共享  后端是几台集群。

直接上配置:

spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:security="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx             
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/task
		http://www.springframework.org/schema/task/spring-task.xsd">
		
	<security:http pattern="/packages/index/**" security="none" />
	<security:http pattern="/packages/pages/**" security="none" />
	<security:http pattern="/packages/sidebarfile.json" security="none" />
	<security:http pattern="/favicon.ico" security="none" />
	<security:http pattern="/goToLogin.html" security="none" />
	<security:http pattern="/index.html" security="none" />
	<security:http pattern="/login.json" security="none" />
	<security:http pattern="/loginPrompt.html" security="none" />
	<security:http pattern="/pseudo_login.html" security="none" />

	<security:http pattern="/mvc/dispatch" create-session="always" auto-config='true'>
		<security:intercept-url pattern="/mvc/dispatch" access="permitAll" />
		<security:csrf disabled="true" />
		<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
        <security:session-management
            session-authentication-strategy-ref="sas" />
		
	</security:http>

	<security:authentication-manager>
		<security:authentication-provider user-service-ref="jbpUserDetailsService" />
	</security:authentication-manager>

	<security:global-method-security pre-post-annotations="enabled" />
	
	<bean id="redirectSessionInformationExpiredStrategy"
		class="org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy">
		<constructor-arg name="invalidSessionUrl" value="/goLogin.html" />
	</bean>
	
	<bean id="concurrencyFilter"
        class="org.springframework.security.web.session.ConcurrentSessionFilter">
        <constructor-arg name="sessionRegistry" ref="sessionRegistry" />
   		<constructor-arg name="sessionInformationExpiredStrategy" ref="redirectSessionInformationExpiredStrategy" />
    </bean>

    <bean id="sas"
        class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
        <constructor-arg>
            <list>
                <bean
                    class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
                    <constructor-arg ref="sessionRegistry" />
                    <property name="maximumSessions" value="1" />
                </bean>
                <bean
                    class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
                </bean>
                <bean
                    class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
                    <constructor-arg ref="sessionRegistry" />
                </bean>
            </list>
        </constructor-arg>
    </bean>


	<bean id="sessionRegistry"
		class="org.springframework.session.security.SpringSessionBackedSessionRegistry">
		<constructor-arg ref="sessionRepository" />
	</bean>
</beans>

 

<bean        class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"></bean>

有时候会报 SessionFixation的问题 导致登录不上去  就是 session 销毁重建的过程失败 没有创建出新的session 就tomcat集群时会报这个问题 没找到解决方式 。可以注释掉这句

<bean        class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"></bean>

让他不走SessionFixation的方法就行 虽然会导致登陆后 sessionid不变 但是内网的项目无所谓了。

 

用的security 5.0.0

之前用了废弃的方法 导致重定向 空指针 

错误配置如下:

<bean id="concurrencyFilter"
        class="org.springframework.security.web.session.ConcurrentSessionFilter">
        <constructor-arg name="sessionRegistry" ref="sessionRegistry" />
          <constructor-arg value="/goLogin.html" />
    </bean>

百度不靠谱 还得上spring-security 官网才行。 上官网一看例子 ok 调试一下源码 立马发现问题

185324_cEPp_3065626.png

旧配置 这个跳转的直接为null导致 500错误。

新配置直接用的response.sendRedirect(url)进行跳转。

登录代码里还得添加手动session注册

@Autowired
	private CompositeSessionAuthenticationStrategy sas;

private void registerTokenIntoSession(User user) throws ServiceException {
		Token token = authorizationService.getUserTokenByUserId(user);
		List<GrantedAuthority> authorities = authorizationService.getAuthorities(token.getFunc());
		Authentication auth = new PreAuthenticatedAuthenticationToken(token.getUser().getAccount(), token.getUser(),
				authorities);
		auth.setAuthenticated(true);
		SecurityContextHolder.getContext().setAuthentication(auth);	
		long loginTime = System.currentTimeMillis();
		HttpSession session = servletRequest.getSession();
		session.setAttribute("tUser", token.getUser());
		session.setAttribute("loginUserCode", token.getUser().getUserCode());
		session.setAttribute("token", token);
		session.setAttribute("loginTime", loginTime);
		session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
		sas.onAuthentication(auth, servletRequest, servletResponse); //重点
		workDTO.put("token", token);
		workDTO.put("loginTime", loginTime);
	}

顺便贴一下 logout

public void logout() {
		HttpSession session = servletRequest.getSession();
		session.removeAttribute("tUser");
		session.removeAttribute("loginUserCode");
		session.removeAttribute("token");
		session.removeAttribute("loginTime");
		Cookie[] cookies = servletRequest.getCookies();
		for(Cookie cookie:cookies){
			if("userId".equals(cookie.getName())){
				Cookie dCookie=new Cookie(cookie.getName(),null);
				dCookie.setValue(null);
				dCookie.setMaxAge(0);//删除登录 cookie
				dCookie.setPath(servletRequest.getContextPath());
				servletResponse.addCookie(dCookie);
			}
		}
		//返回新的logoutToken session标记
		CommonHelper.setLogOutToken(servletResponse,servletRequest,session,true,"logout");
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		new SecurityContextLogoutHandler().logout(ActionContext.getContext().getServletRequest(),
				ActionContext.getContext().getServletResponse(), auth);
		
	}

 

转载于:https://my.oschina.net/u/3065626/blog/1790826

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值