Spring Security构建Rest服务-1100-单机Session管理
Session失效时间:
springboot配置session失效时间,只需要在application.properties里配置
#session超时时间,低于60秒按60秒
server.session.timeout = 60
如果想自己定义session失效的提示信息,需要配置:
@Configuration //这是一个配置
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{
//版本二:可配置的登录页
@Override
protected void configure(HttpSecurity http) throws Exception {
//~~~-------------> 图片验证码过滤器 <------------------
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
//验证码过滤器中使用自己的错误处理
validateCodeFilter.setAuthenticationFailureHandler(imoocAuthenticationFailureHandler);
//配置的验证码过滤url
validateCodeFilter.setSecurityProperties(securityProperties);
validateCodeFilter.afterPropertiesSet(); //~~~-------------> 短信验证码过滤器 <------------------
SmsCodeFilter smsCodeFilter = new SmsCodeFilter();
//验证码过滤器中使用自己的错误处理
smsCodeFilter.setAuthenticationFailureHandler(imoocAuthenticationFailureHandler);
//配置的验证码过滤url
smsCodeFilter.setSecurityProperties(securityProperties);
smsCodeFilter.afterPropertiesSet(); //实现需要认证的接口跳转表单登录,安全=认证+授权
//http.httpBasic() //这个就是默认的弹框认证
//
http
.addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class)
// .apply(imoocSocialSecurityConfig)//社交登录
// .and()
//把验证码过滤器加载登录过滤器前边
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
//----------表单认证相关配置---------------
.formLogin()
.loginPage(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL) //处理用户认证BrowserSecurityController
//登录过滤器UsernamePasswordAuthenticationFilter默认登录的url是"/login",在这能改
.loginProcessingUrl(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_FORM)
.successHandler(imoocAuthenticationSuccessHandler)//自定义的认证后处理器
.failureHandler(imoocAuthenticationFailureHandler) //登录失败后的处理
.and()
//------------记住我相关配置 -------------
.rememberMe()
.tokenRepository(persistentTokenRepository())//TokenRepository,登录成功后往数据库存token的
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//记住我秒数
.userDetailsService(userDetailsService) //记住我成功后,调用userDetailsService查询用户信息
.and()//-----------session相关配置---------------
.sessionManagement()
// .invalidSessionStrategy(invalidSessionStrategy)
// .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
.invalidSessionUrl(SecurityConstants.SESSION_INVALID_PAGE) //session失效跳转地址,如果简单的处理只要这一个就够了
// .maximumSessions(1) //一个用户只能登录一次,踢出前边登录用户
// .maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())//阻止在登录
// .expiredSessionStrategy(sessionInformationExpiredStrategy) //session失效策略
.and() //?俩and为啥呢
// .and()
//-----------授权相关的配置 ---------------------
.authorizeRequests()
// /authentication/require:处理登录,securityProperties.getBrowser().getLoginPage():用户配置的登录页
.antMatchers(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
securityProperties.getBrowser().getLoginPage(),//放过登录页不过滤,否则报错
SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE,
SecurityConstants.SESSION_INVALID_PAGE,
SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX+"/*").permitAll() //验证码
.anyRequest() //任何请求
.authenticated() //都需要身份认证
.and()
.csrf().disable() //关闭csrf防护
.apply(smsCodeAuthenticationSecurityConfig);//把短信验证码配置应用上
}
}
public static final String SESSION_INVALID_PAGE = "/session/invalid";
@GetMapping("/session/invalid")
@ResponseStatus(code = HttpStatus.UNAUTHORIZED)
public SimpleResponse toSessionInvalidPage(){
String message = "session 失效!";
return new SimpleResponse(message);
}
一个账户同时默认是可以在多处登录的,如果想要后边的登录踢出前边的登录,只要放开 .maximumSessions(1) 这句配置即可。
session并发控制:
也可以自定义session失效策略,自定义一个类ImoocExpiredSessionStrategy2:
package com.imooc.security.browser.session; import java.io.IOException; import javax.servlet.ServletException; import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy; /**
* session失效策略,简单版本
* ClassName: ImoocExpiredSessionStrategy
* @Description: TODO
* @author lihaoyang
* @date 2018年3月8日
*/
public class ImoocExpiredSessionStrategy2 implements SessionInformationExpiredStrategy{ /**
* SessionInformationExpiredEvent:session失效事件,能拿到request、response
*/
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
//可以从event中拿到request中的信息
event.getResponse().setContentType("application/json;charset=UTF-8");
event.getResponse().getWriter().write("并发登录!");
} }
加上配置:
.sessionManagement()
// .invalidSessionStrategy(invalidSessionStrategy)
// .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions()) .invalidSessionUrl(SecurityConstants.SESSION_INVALID_PAGE) //session失效跳转地址,如果简单的处理只要这一个就够了
.maximumSessions(1) //一个用户只能登录一次,踢出前边登录用户
.expiredSessionStrategy(new ImoocExpiredSessionStrategy2()) //简洁版session失效策略
此时如果第二次登录,第一个登录就会提示:

如果想阻止多处登录,可以加上这句配置:
.sessionManagement()
// .invalidSessionStrategy(invalidSessionStrategy)
// .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions()) .invalidSessionUrl(SecurityConstants.SESSION_INVALID_PAGE) //session失效跳转地址,如果简单的处理只要这一个就够了
.maximumSessions(1) //一个用户只能登录一次,踢出前边登录用户
.expiredSessionStrategy(new ImoocExpiredSessionStrategy2()) //简洁版session失效策略
.maxSessionsPreventsLogin(true) //阻止并发登录
此时如果多出登录,后者就会提示

重构:将session失效策略自己实现
/**
*
*/
package com.imooc.security.browser.session; import java.io.IOException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.security.web.session.InvalidSessionStrategy; /**
* @author zhailiang
*
*/
public class ImoocInvalidSessionStrategy extends AbstractSessionStrategy implements InvalidSessionStrategy { public ImoocInvalidSessionStrategy(String invalidSessionUrl) {
super(invalidSessionUrl);
} @Override
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
onSessionInvalid(request, response);
} }
session过期策略:
package com.imooc.security.browser.session; import java.io.IOException; import javax.servlet.ServletException; import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy; /**
* session失效策略
* ClassName: ImoocExpiredSessionStrategy
* @Description: TODO
* @author lihaoyang
* @date 2018年3月8日
*/
public class ImoocExpiredSessionStrategy extends AbstractSessionStrategy implements SessionInformationExpiredStrategy
{ /**
* SessionInformationExpiredEvent:session失效事件,能拿到request、response
*/
// @Override
// public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
// event.getResponse().setContentType("application/json;charset=UTF-8");
// event.getResponse().getWriter().write("并发登录!");
// } public ImoocExpiredSessionStrategy(String invalidSessionUrl) {
super(invalidSessionUrl);
} /* (non-Javadoc)
* @see org.springframework.security.web.session.SessionInformationExpiredStrategy#onExpiredSessionDetected(org.springframework.security.web.session.SessionInformationExpiredEvent)
*/
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
onSessionInvalid(event.getRequest(), event.getResponse());
} /* (non-Javadoc)
* @see com.imooc.security.browser.session.AbstractSessionStrategy#isConcurrency()
*/
@Override
protected boolean isConcurrency() {
return true;
} }
AbstractSessionStrategy:
/**
*
*/
package com.imooc.security.browser.session; import java.io.IOException; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert; import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.security.browser.support.SimpleResponse; /**
* @author zhailiang
*
*/
public class AbstractSessionStrategy { private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 跳转的url
*/
private String destinationUrl;
/**
* 重定向策略
*/
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
/**
* 跳转前是否创建新的session
*/
private boolean createNewSession = true; private ObjectMapper objectMapper = new ObjectMapper(); /**
* @param invalidSessionUrl
* @param invalidSessionHtmlUrl
*/
public AbstractSessionStrategy(String invalidSessionUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'");
this.destinationUrl = invalidSessionUrl;
} /*
* (non-Javadoc)
*
* @see org.springframework.security.web.session.InvalidSessionStrategy#
* onInvalidSessionDetected(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
protected void onSessionInvalid(HttpServletRequest request, HttpServletResponse response) throws IOException { if (createNewSession) {
request.getSession();
} String sourceUrl = request.getRequestURI();
String targetUrl; if (StringUtils.endsWithIgnoreCase(sourceUrl, ".html")) {
targetUrl = destinationUrl;//+".html";
logger.info("session失效,跳转到"+targetUrl);
redirectStrategy.sendRedirect(request, response, targetUrl);
}else{
String message = "session已失效";
if(isConcurrency()){
message = message + ",有可能是并发登录导致的";
}
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse(message)));
} } /**
* session失效是否是并发导致的
* @return
*/
protected boolean isConcurrency() {
return false;
} /**
* Determines whether a new session should be created before redirecting (to
* avoid possible looping issues where the same session ID is sent with the
* redirected request). Alternatively, ensure that the configured URL does
* not pass through the {@code SessionManagementFilter}.
*
* @param createNewSession
* defaults to {@code true}.
*/
public void setCreateNewSession(boolean createNewSession) {
this.createNewSession = createNewSession;
} }
配置:
.sessionManagement()
//++++++=基本这样配置++++++++
// .invalidSessionUrl(SecurityConstants.SESSION_INVALID_PAGE) //session失效跳转地址,如果简单的处理只要这一个就够了
// .maximumSessions(1) //一个用户只能登录一次,踢出前边登录用户
// .expiredSessionStrategy(new ImoocExpiredSessionStrategy2()) //简洁版session失效策略
// .maxSessionsPreventsLogin(true) //阻止并发登录 //
//++++++++重构后+++++++
.invalidSessionStrategy(invalidSessionStrategy)
.maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
.maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())//阻止在登录
.expiredSessionStrategy(sessionInformationExpiredStrategy) //session失效策略
而且变量都做成了可配置的,具体的代码放在了github:
https://github.com/lhy1234/spring-security
Spring Security构建Rest服务-1100-单机Session管理的更多相关文章
- Spring Security构建Rest服务-1300-Spring Security OAuth开发APP认证框架之JWT实现单点登录
基于JWT实现SSO 在淘宝( https://www.taobao.com )上点击登录,已经跳到了 https://login.taobao.com,这是又一个服务器.只要在淘宝登录了,就能直接访 ...
- Spring Security构建Rest服务-1202-Spring Security OAuth开发APP认证框架之重构3种登录方式
SpringSecurityOAuth核心源码解析 蓝色表示接口,绿色表示类 1,TokenEndpoint 整个入口点,相当于一个controller,不同的授权模式获取token的地址都是 /oa ...
- Spring Security构建Rest服务-1200-SpringSecurity OAuth开发APP认证框架
基于服务器Session的认证方式: 前边说的用户名密码登录.短信登录.第三方登录,都是普通的登录,是基于服务器Session保存用户信息的登录方式.登录信息都是存在服务器的session(服务器的一 ...
- Spring Security构建Rest服务-1001-spring social开发第三方登录之spring social基本原理
OAuth协议是一个授权协议,目的是让用户在不将服务提供商的用户名密码交给第三方应用的条件下,让第三方应用可以有权限访问用户存在服务提供商上的资源. 接着上一篇说的,在第三方应用获取到用户资源后,如果 ...
- Spring Security构建Rest服务-0900-rememberMe记住我
Spring security记住我基本原理: 登录的时候,请求发送给过滤器UsernamePasswordAuthenticationFilter,当该过滤器认证成功后,会调用RememberMeS ...
- Spring Security构建Rest服务-1201-Spring Security OAuth开发APP认证框架之实现服务提供商
实现服务提供商,就是要实现认证服务器.资源服务器. 现在做的都是app的东西,所以在app项目写代码 认证服务器: 新建 ImoocAuthenticationServerConfig 类,@Ena ...
- Spring Security构建Rest服务-0702-短信验证码登录
先来看下 Spring Security密码登录大概流程,模拟这个流程,开发短信登录流程 1,密码登录请求发送给过滤器 UsernamePasswordAuthenticationFilter 2,过 ...
- Spring Security构建Rest服务-0800-Spring Security图片验证码
验证码逻辑 以前在项目中也做过验证码,生成验证码的代码网上有很多,也有一些第三方的jar包也可以生成漂亮的验证码.验证码逻辑很简单,就是在登录页放一个image标签,src指向一个controller ...
- Spring Security构建Rest服务-0702-个性化用户认证流程2
登录成功后的处理AuthenticationSuccessHandler: 认证成功后,默认情况下spring security会继续访问之前访问的url,如果想自定义处理逻辑,用默认的就不行了.此时 ...
随机推荐
- python pip国内源
pip国内的这个源最快 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 修改源方法: 临时使用: 可以在使用pip的时候在后面加上-i参数,指定pip ...
- Can not find the tag library descriptor for "/struts-tags"`
1.查看struts.xml路径是否错误,要放在src下, 2.缺少struts-tags.tld (1)查找方式: (2)找到此包,然后右键用解压缩文件打开. (3)然后你会看到很多的源码,找到红圈 ...
- linux上安装tomcat
这里采用离线解压tar.gz的方式安装 下载: wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.0.33/bin/apache-tomc ...
- vs2015 cmd.exe已退出 代码为1
https://blog.csdn.net/changbin91/article/details/42874377?utm_source=blogxgwz0 https://blog.csdn.net ...
- day06(Collection,List,ArrayList,LinkedList,iterator迭代器,增强for)
Collection 接口 方法实现 boolean add(Object o);//添加 boolean remove(Object o);//移除 修改方法 让实现类自己去实现修 ...
- hdu3333 Turing Tree 2016-09-18 20:53 42人阅读 评论(0) 收藏
Turing Tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- node.excel
今天突然间想起来用node如何操作excel,记得之前用Java的poi操作excel,感觉特别爽,计算机代替人的工作,非常有用,所以决定摸索一下. 在网上找了各种模块,有导出的,有导入的,有转为js ...
- WinForm如何去掉右边和下边的白边
系统给的窗体样式都缺乏美感,想要漂亮的UI只能自己做,很容易实现 1.新建窗体,设置FormBorder为None 这时的窗体就只有一个Panel(Form自带的默认Panel),没有边框,没有标题栏 ...
- C# 图像自动切换
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- C# 生产成条形码3种方法
首先效果: 1:首先下载BarcodeLib.dll 下载地址 http://pan.baidu.com/share/link?shareid=2590968386&uk=2148890391 ...