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,如果想自定义处理逻辑,用默认的就不行了.此时 ...
随机推荐
- if_elseif
用MATLAB写了个这样的程序 if ((0 < pwr <=2) ) wf_temp1 = round(temp_wf0/2^7); elseif( (2 < pwr<= 4 ...
- qq强制聊天工具
当你想和别人聊天, 别人有不理你的时候可以用上哦!!!特别是情人吵架的时候, 呵呵 复制下面的代码: @echo off title DIY-QQ强制聊天工具color 0a echo. echo. ...
- JVM,Java虚拟机基础知识新手入门教程(超级通熟易懂)
作者:请叫我红领巾,转载请注明出处http://www.cnblogs.com/xxzhuang/p/7453746.html,简书地址:http://www.jianshu.com/p/b963b3 ...
- 2013多校联合3 G The Unsolvable Problem(hdu 4627)
2013-07-30 20:35 388人阅读 评论(0) 收藏 举报 http://acm.hdu.edu.cn/showproblem.php?pid=4627 The Unsolvable Pr ...
- 安装及使用Eclipse Maven插件的经验
Eclipse Maven插件的站点目前已经迁移到了Eclipse主站上:http://eclipse.org/m2e/ 其安装方法也非常简单,通过Eclipse访问下面的URL:http://dow ...
- OneDrive不能上了?DNS被污染,解决方法很简单
http://www.expreview.com/34434.html 除了LINE以外,最近微软的OneDrive云存储服务也出现访问故障,不过@月光博客 表示它只是受到DNS污染,被解析为无法访问 ...
- WPF中得到一个控件相对其他控件的坐标
加入想得到按钮btnTest左上角相对于主窗体winTest的坐标,可以用如下方法:btnTest.TranslatePoint(new Point(0, 0), winTest)这个方法返回一个Po ...
- 常用kubectl命令总结
command kubectl kubectl 输出格式 显示Pod的更多信息 kubectl get pod <pod-name> -o wide 以yaml格式显示Pod的详细信息 k ...
- NLayerAppV3--基础结构层(Cross-Cutting部分)
回顾:NLayerAppV3是一个使用.net 2.1实现的经典DDD的分层架构的项目. NLayerAppV3是在NLayerAppV2的基础上,使用.net core2.1进行重新构建的:它包含了 ...
- 使用base64转码的方式上传图片
1.前端html代码 <input style="width:100%" onchange="loadpicture(1)" type="fil ...