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,如果想自定义处理逻辑,用默认的就不行了.此时 ...
随机推荐
- jedis 链接池使用(转)
Jedis作为redis的最佳客户端,它提供了连接池的特性,“连接池”在通常情况下可以有效的提高应用的通信能力,并且这是一种良好的设计模式.Jedis的连接池设计基于apache commons-po ...
- scrapy windows 安装
windows 7 系统下参照官网安装总是会提示出错,现在整理一下安装的流程 1.安装 python 2.7,添加环境变量 C:\Python27\;C:\Python27\Scripts\; 在 C ...
- Tomcat 环境变量配置
1.变量和常量 i 和 0 2.环境变量 cmd >set 查看所有环境变量 %PATH% 系统指定可执行文件的搜索路径,可以是 .exe .bat String path=“C:\WINDOW ...
- tar、7z(7zip)压缩/解压缩指令的使用
本文介绍tar.7z指令的使用方法 tar指令 在Linux中,使用的最多的压缩/解压缩指令就是tar指令了. tar指令用来将多个文件/目录结构打包.在实际使用中,往往使用tar对压缩的支持,即同时 ...
- 设置p标签可编辑
一,只可编辑,粘贴复制字段长度不正常 <p contenteditable="true" >这是一个可编辑内容的p标签啦啦~</p> 二,可编辑,可粘贴复制 ...
- string转换成char*
string 是c++标准库里面其中一个,封装了对字符串的操作 把string转换为char* 有3中方法: 1.data 如: string str="abc"; char *p ...
- Postman - 測試 API 的好工具
POSTMAN in Google APP Store 因為工作的關係,常常寫一些 API 供 APP 使用.以前傻傻的,每次測試的時候都會自己刻一個 HTML 的表單,一個一個填入 input ,接 ...
- hdu 4004 最大值最小化
http://acm.hdu.edu.cn/showproblem.php?pid=4004 一条线段长度为L,线段上有n个点,最多选取 m-1 个点,使得包括线段端点在内的相邻点之间的最大距离值最小 ...
- NOR Flash的学习
NOR Flash简介 NOR FLASH是INTEL在1988年推出的一款商业性闪存芯片,它需要很长的时间进行抹写,大半生它能够提供完整的寻址与数据总线,并允许随机存取存储器上的任何区域,而且 ...
- KbmMW安装
系统环境及相关软件版本: Windows 7 64位, Delphi XE Version 15.0.3953.35171 , Indy 10.5.7 kbmMW4.90.04 , kbmMemTab ...