Spring Security 梳理 - session
Spring Security默认的行为是每个登录成功的用户会新建一个Session。这也就是下面的配置的效果:
<http create-session="ifRequired">...</http>
这貌似没有问题,但其实对大规模的网站是致命的。用户越多,新建的session越多,最后的结果是JVM内存耗尽,你的web服务器彻底挂了。有session的另外一个严重的问题是scalability能力,用户压力上来了不能马上新建一台Jetty/Tomcat服务器,因为要考虑Session同步的问题。 先来看看Session过多导致的Jetty JVM 内存耗尽:
Spring Security 3.1开始支持stateless authentication(具体查看 What‘s new in Spring Security 3.1?),配置方法是:
<http create-session="stateless">
<!-- ... -->
</http>
主要是在RESTful API,无状态的web调用的stateless authentication。
这个配置的意思是:Spring Security对登录成功的用户不会创建Session了,你的application也不会允许新建session,而且Spring Security会跳过所有的 filter chain:HttpSessionSecurityContextRepository, SessionManagementFilter, RequestCacheFilter.
也就是说每个请求都是无状态的独立的,需要被再次认证re-authentication。开销显然是增大了,因为每次请求都必须在服务器端重新认证并建立用户角色和权限的上下文。
Stateless的RESTful authentication认证
刚才说了,配置为stateless的使用场景,例如RESTful api,其每个请求都是无状态的独立的,需要被再次认证re-authentication。操作层面,具体做法是:在每一个REST的call的头header(例如:@HeaderParam annotation. 例子: @HeaderParam.)都带user token 和 application ID,然后在服务器端对每一请求进行re-authentication. (注意:把token放在uri中是糟糕的做法,首先是安全的原因,其次是cache的原因,尽量放在head中)可以写一个拦截器来实现:

@Provider
@ServerInterceptor
public class RestSecurityInterceptor implements PreProcessInterceptor { @Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
throws UnauthorizedException { String token = request.getHttpHeaders().getRequestHeader("token").get(0); // user not logged-in?
if (checkLoggedIn(token)) {
ServerResponse response = new ServerResponse();
response.setStatus(HttpResponseCodes.SC_UNAUTHORIZED);
MultivaluedMap<String, Object> headers = new Headers<Object>();
headers.add("Content-Type", "text/plain");
response.setMetadata(headers);
response.setEntity("Error 401 Unauthorized: "
+ request.getPreprocessedPath());
return response;
}
return null;
}
}

Spring Security配置文件:

<security:http realm="Protected API" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="CustomAuthenticationEntryPoint">
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/authenticate" access="permitAll"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http> <bean id="CustomAuthenticationEntryPoint"
class="com.demo.api.support.spring.CustomAuthenticationEntryPoint" /> <bean class="com.demo.api.support.spring.AuthenticationTokenProcessingFilter"
id="authenticationTokenProcessingFilter">
<constructor-arg ref="authenticationManager" />
</bean>

CustomAuthenticationEntryPoint:

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Authentication token was either missing or invalid." );
}
}

AuthenticationTokenProcessingFilter:

@Autowired UserService userService;
@Autowired TokenUtils tokenUtils;
AuthenticationManager authManager; public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) {
this.authManager = authManager;
} @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
@SuppressWarnings("unchecked")
Map<String, String[]> parms = request.getParameterMap(); if(parms.containsKey("token")) {
String token = parms.get("token")[0]; // grab the first "token" parameter // validate the token
if (tokenUtils.validate(token)) {
// determine the user based on the (already validated) token
UserDetails userDetails = tokenUtils.getUserFromToken(token);
// build an Authentication object with the user's info
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request));
// set the authentication into the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(authentication));
}
}
// continue thru the filter chain
chain.doFilter(request, response);
}
}

TokenUtils:

public interface TokenUtils {
String getToken(UserDetails userDetails);
String getToken(UserDetails userDetails, Long expiration);
boolean validate(String token);
UserDetails getUserFromToken(String token);
}

Spring Security其它方面
其他的比如concurrent Session,意思是同一个用户允许同时在线(不同地点)的数量。还有Session劫持的防止, auto-remember等,具体参考这个网页。
参考:https://www.cnblogs.com/Mainz/p/3230077.html
Spring Security 梳理 - session的更多相关文章
- spring security控制session
spring security控制session本文给你描述在spring security中如何控制http session.包括session超时.启用并发session以及其他高级安全配置. 创 ...
- Spring Security 之Session管理配置
废话不多说,直接上代码.示例如下: 1. 新建Maven项目 session 2. pom.xml <project xmlns="http://maven.apache.o ...
- Spring Security 梳理 - DelegatingFilterProxy
可能你会觉得奇怪,我们在web应用中使用Spring Security时只在web.xml文件中定义了如下这样一个Filter,为什么你会说是一系列的Filter呢? <filter> ...
- spring security梳理
核心服务:AuthenticationManager,UserDetailsService和AccessDecisionManager The AuthenticationManager, Provi ...
- Spring Security入门(3-8)Spring Security获取session中的UserDetail
- 关于Spring Security中无Session和无状态stateless
Spring Security是J2EE领域使用最广泛的权限框架,支持HTTP BASIC, DIGEST, X509, LDAP, FORM-AUTHENTICATION, OPENID, CAS, ...
- Spring Security研究(2)-高级web特性
1, 添加 HTTP/HTTPS 信道安全 <http> <intercept-url pattern="/secure/**" access="ROL ...
- [Java][Spring][scurity]同步session控制,防止一个用户多次登录
[Spring][scurity]同步session控制.防止一个用户多次登录 假设你希望限制单个用户仅仅能登录到你的程序一次,Spring Security通过加入以下简单的部分支持这个功能. 1. ...
- SpringBoot集成Spring Security(7)——认证流程
文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...
随机推荐
- 常用Linux备份
用于备份的Tar 备份工具Tar是以前备份文件的可靠方法,几乎可以工作于任何环境中,Linux老用户一般都信赖它. Linux中以.tar结尾的文件都是用tar创建的.它的使用超出了单纯的备份,可用来 ...
- python爬取豆瓣首页热门栏目详细流程
记录一下爬取豆瓣热门专栏的经过,通过这篇文章,你能学会requests,HTMLParser,json的基本使用,以及爬取网页内容的基本思路. 使用模块 1,获取豆瓣首页代码:首先我们需要访问豆瓣页面 ...
- 带你了解什么是Push消息推送
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 如果有看我最近文章的同学可能就知道我在公司负责的是一 ...
- mysql中的截取函数及其实例
一.mysql截取字符串函数 1.left(str,length) 从左边截取length 2.right(str,length)从右边截取length 3.substring(str,index)当 ...
- FastDFS初印象
是什么? FastDFS是一个轻量级分布式文件系统. 能干嘛? 对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等. 相关概念 ...
- ASP.NET Core中使用Csp标头对抗Xss攻击
内容安全策略(CSP)是一个增加的安全层,可帮助检测和缓解某些类型的攻击,包括跨站点脚本(XSS)和数据注入攻击.这些攻击用于从数据窃取到站点破坏或恶意软件分发的所有内容(深入CSP) 简而言之,CS ...
- Python 基础(四)
open函数 open(name[,mode[,buffering[,encoding]]]) mode(访问模式): -1 : r(只读) w(只写,若文件存在则覆盖) a(追加) rb(二进制只读 ...
- Badboy - 导出脚本,用于JMeter性能测试
参考: http://leafwf.blog.51cto.com/872759/1131119 http://www.51testing.com/html/00/130600-1367743.html ...
- SPOJ - QTREE4 Query on a tree IV 边分治
题目传送门 题意:有一棵数,每个节点有颜色,黑色或者白色,树边有边权,现在有2个操作,1修改某个点的颜色, 2询问2个白点的之前的路径权值最大和是多少. 题解: 边分治思路. 1.重构图. 因为边分治 ...
- lightoj 1044 - Palindrome Partitioning(需要优化的区间dp)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1044 题意:求给出的字符串最少能分成多少串回文串. 一般会想到用区间dp暴力3个for ...