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:HttpSessionSecurityContextRepositorySessionManagementFilterRequestCacheFilter.

也就是说每个请求都是无状态的独立的,需要被再次认证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的更多相关文章

  1. spring security控制session

    spring security控制session本文给你描述在spring security中如何控制http session.包括session超时.启用并发session以及其他高级安全配置. 创 ...

  2. Spring Security 之Session管理配置

    废话不多说,直接上代码.示例如下: 1.   新建Maven项目  session 2.   pom.xml <project xmlns="http://maven.apache.o ...

  3. Spring Security 梳理 - DelegatingFilterProxy

    可能你会觉得奇怪,我们在web应用中使用Spring Security时只在web.xml文件中定义了如下这样一个Filter,为什么你会说是一系列的Filter呢?    <filter> ...

  4. spring security梳理

    核心服务:AuthenticationManager,UserDetailsService和AccessDecisionManager The AuthenticationManager, Provi ...

  5. Spring Security入门(3-8)Spring Security获取session中的UserDetail

  6. 关于Spring Security中无Session和无状态stateless

    Spring Security是J2EE领域使用最广泛的权限框架,支持HTTP BASIC, DIGEST, X509, LDAP, FORM-AUTHENTICATION, OPENID, CAS, ...

  7. Spring Security研究(2)-高级web特性

    1, 添加 HTTP/HTTPS 信道安全 <http> <intercept-url pattern="/secure/**" access="ROL ...

  8. [Java][Spring][scurity]同步session控制,防止一个用户多次登录

    [Spring][scurity]同步session控制.防止一个用户多次登录 假设你希望限制单个用户仅仅能登录到你的程序一次,Spring Security通过加入以下简单的部分支持这个功能. 1. ...

  9. SpringBoot集成Spring Security(7)——认证流程

    文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...

随机推荐

  1. unity之截屏功能

    1.全屏截图 方法一:在unity的API中,unity给我们提供了一个现成的API  :  Application.CaptureScreenshot(imagename). 但是这个API虽然简单 ...

  2. Codeforces 1204C

    题意略. 思路:我的想法是逐步地找出这个序列中的重要点,我要判断当前这个点能不能删去,就要看上一个重要点和当前这个点 i 在序列中的下一个点 i + 1之间的距离 是否是最短距离,如果是,那么我们就可 ...

  3. three.js实现球体地球2018年全球GDP前十国家标记

    概况如下: 1.SphereGeometry实现自转的地球: 2.THREE.Math.degToRad,Math.sin,Math.cos实现地图经纬度与三位坐标x,y,z之间的转换: 3.Imag ...

  4. Shiro的几个关键类

    Shiro在于Spring集成中,需要配置SecurityManager,Realm,ShiroFilterFactoryBean这三个类.在Web环境中SecurityManager一般配置Defa ...

  5. 2. Sentinel源码分析—Sentinel是如何进行流量统计的?

    这一篇我还是继续上一篇没有讲完的内容,先上一个例子: private static final int threadCount = 100; public static void main(Strin ...

  6. Python Web Flask源码解读(四)——全局变量

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  7. .net core api服务端跨域配置

    第1步:添加包引用(.net core 2.2 已自带此包,可跳过此步骤) Install-Package Microsoft.AspNetCore.Cors 第2步:在Startup.cs文件的Co ...

  8. H5调用相机和相册更换头像

    需求:H5调用手机的相机和相册从而实现更换头像的功能 这个功能是很常用的一个功能,因此做一个记录. 1.在头像img下加一个文件输入框 <input type="file" ...

  9. 2019nc#6

    https://ac.nowcoder.com/acm/contest/886#question 题号 标题 已通过代码 题解/讨论 通过率 团队的状态 A Garbage Classificatio ...

  10. UVALive 7264 Kejin Game 网络流+最小割

    Kejin Game 题意:一个人有一颗技能树, 现在它想修练到某个技能 (假设为x), 现在修一个技能有3种方式: 1, 将该技能的前置技能都学完了,才能学该技能. 2, 取消一个技能 与 另一个技 ...