Spring Security是个安全框架众所周知,同时也提供了一整套基于Web的认证机制和安全服务,当然如果你要通过其他协议的来实现安全服务,你也可以使用SpringSecurity来帮助你。
今天主要是讲解基于web端的安全认证机制,其他的留着以后有空再整理成博文。
首先SpringSecurity Web是基于它所提供的一整套Filter链来实现的,我们来看下它所提供的有哪些Filter:
在列表中可以看到,这些Filter链是有序的,而且自身所提供的Filter是无法更改顺序的,so what???当然,你都能任意更改顺序了,那我怎么能保证在不同的filter中拿到正确的数据呢,是吧?这些filter是SpringSecurity在启动时会默认注入到容器中的,你可以根据自身业务的需要在这些filter的before或after插入自己设计的filter。
那每一个Filter具体是做了什么工作,大家自行去查阅,这不是今天讲的重点,今天着重讲基于web的认证机制。
先来看看SpringSecurity中认证时的几个关键类:
org.springframework.security.web.context.SecurityContextRepository
org.springframework.security.web.context.SecurityContextPersistenceFilter
org.springframework.security.core.context.SecurityContextHolder
org.springframework.security.core.context.SecurityContextHolderStrategy
org.springframework.security.core.Authentication
首先来看下作为用户在login时的交互图,这个图确实太大了,已经尽量缩小了,但还是很大。
从图中我们可以看到,用户在请求服务时,首先会经过图中的SecurityContextPersistenceFilter(其实这个类在Filter链中是第二个被处理的),这个类是干嘛的呢,主要就是用于设置SecurityContext到SecurityContextHolder中,具体的我们通过图和源码一点点分析
首先看看SecurityContextPersistenceFilter.class
public SecurityContextPersistenceFilter() { this(new HttpSessionSecurityContextRepository()); } public SecurityContextPersistenceFilter(SecurityContextRepository repo) { this.repo = repo; }
我们可以看到这个类的构造方法是需要设置SecurityContextRepository的,默认会设置为HttpSessionSecurityContextRepository.class,这个东西是拿来干嘛的?是用于设置SecurityContext的存储机制的,这个类对于你每次使用SecurityContextHolder在getContext时是否能拿到正确的context起到了关键性的作用。可以看到默认使用HttpSession来实现SecutiryContext的存储。
接下来我们看看doFilter中干了些什么事:
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,response); // 这里可以看到从repo中取得SecurityContext,默认是从HttpSession里获取 SecurityContext contextBeforeChainExecution = repo.loadContext(holder); try { // 同时在这里将创建好的SecurityContext设置到SecurityContextHolder中 SecurityContextHolder.setContext(contextBeforeChainExecution); chain.doFilter(holder.getRequest(), holder.getResponse()); }
再来看一下repo.loadCotext的实现。
// 先从Session里去读取是否存在SecurityContext SecurityContext context = readSecurityContextFromSession(httpSession); // 如果不存在将创建一个空的SecurityContext if (context == null) { context = generateNewContext(); } return context; protected SecurityContext generateNewContext() { return SecurityContextHolder.createEmptyContext(); } private SecurityContext readSecurityContextFromSession(HttpSession httpSession) { Object contextFromSession = httpSession.getAttribute(springSecurityContextKey); }
在这里可以看到如果Session是一个新的话,这里的ScurityContext会从SecurityContextHolder中去创建,在SecurityContextHolder中可以看到默认会通过ThreadLocalSecurityContextHolderStrategy创建一个基于ThreadLocal存储线程安全的SecurityContext,那当前线程中所拿到的SecurityContext均是同一个实例。
现在知道了SecurityContext是如何创建了之后,再回头来看SecurityContextPersistenceFilter中的doFilter实现
try { // 在这里将创建好的SecurityContext设置到SecurityContextHolder中 SecurityContextHolder.setContext(contextBeforeChainExecution); chain.doFilter(holder.getRequest(), holder.getResponse()); }
现在已经在chain.doFilter()之前已经完成了对SecurityContext的设置,接下来过滤器链继续执行,如果你在配置SecurityConfig中使用了UsernamePasswordAuthenticationFilter.class来实现对用户的认证,那我们将会进入到UsernamePasswordAuthenticationFilter的doFilter来实现认证
Authentication authResult; try { authResult = attemptAuthentication(request, response); if (authResult == null) { // return immediately as subclass has indicated that it hasn't completed // authentication return; } sessionStrategy.onAuthentication(authResult, request, response); } successfulAuthentication(request, response, chain, authResult); protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { if (logger.isDebugEnabled()) { logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult); } SecurityContextHolder.getContext().setAuthentication(authResult); rememberMeServices.loginSuccess(request, response, authResult); // Fire event if (this.eventPublisher != null) { eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent( authResult, this.getClass())); } successHandler.onAuthenticationSuccess(request, response, authResult); }
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }
一旦attemptAuthentication认证通过之后,可以在successfulAuthentication方法中可以看到调用了SecurityContextHolder.getContext().setAuthentication(authResult)来完成对用户的认证,到这里已经完成了基于SpringSecurity所提供的一套web完整的认证过程。
在这里就不对UsernamePasswordAuthenticationFilter里的认证机制做详细的阐述了,大家有兴趣的话自己去翻源码查看吧。还是比较简单里,里面设计到了AuthenticationManager、AuthenticationProvider、UserDetailsService等相关的类。
如果你使用的restful接口来实现认证的话,你也可以在验证之后构造一个Authentication实例,再通过SecurityContextHolder.getContext().setAuthentication( authentication )来实现对SpringSecurity的认证。
讲到这里大家对spring security的认证机制应该有一定的认识了吧,如果有什么讲得不到位的地方,欢迎大家交流~
相关推荐
Spring security认证授权例子,自动创建数据库,在SysUser类增加字段,即可动态增加数据库对应表sys_user字段(前提是要删除原表,启动应用时才会重建表)
1.本项目为SpringCloud Gateway的微服务框架,整合了SpringSecurity,微服务间使用Redis来获取登陆的用户信息。 2.由于Gat
springboot+ spring security实现登录认证
基于springboot+SpringSecurity的一款权限认证系统源码+数据库.zip基于springboot+SpringSecurity的一款权限认证系统源码+数据库.zip基于springboot+SpringSecurity的一款权限认证系统源码+数据库.zip基于springboot...
Spring security认证与授权(一)源代码
Spring Security 演讲PPT(演讲嘉宾:张明星) WebSphere技术专家沙龙在广州圆满举办,WSC超级版主Fastzch(张明星)担任本次沙龙的演讲嘉宾,他给广州的WebSphere技术专家带来了以“Spring Security ”为主题的...
Spring Security三份资料,实战Spring Security 3.x.pdf;Spring Security 3.pdf;Spring Security使用手册.pdf
Spring Security:spring家族一员。是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转...
Spring boot+Spring Security Oauth2.0,Sprint cloud+Spring Security Oauth2集成。四种认证方式。附带有代码,和案例,案例,还有视频链接。我保证看完就回,如果视频链接失效,评论回复我,我单独再给你一份。
要实现的效果: 1、用户及用户的权限保存在数据库中。 2、url及所需的权限保存在数据库中,系统加载时从数据库中获取。 https://blog.csdn.net/u014572215/article/details/80309161
springsecurity是一个功能强大且高度可定制的身份验证和访问控制框架。springsecurity是一个专注于为Java应用程序提供身份验证和授权的框架。与所有Spring项目一样,Spring安全性的真正威力在于它可以很容易地扩展以...
SpringBoot+SpringSecurity整合示例代码,实现了从数据库中获取信息进行登录认证和权限认证。 本项目为idea工程,请用idea2019导入(老版应该也可以)。 本项目用户信息所需sql文件,在工程的resources文件夹下,...
Spring Security OAuth2.0学习笔记 什么是认证、授权、会话。 ... 基于session认证机制的运作流程。 基于token认证机制的运作流程。 ...分布式系统认证需要解决的问题? 掌握学习方法,掌握思考方式。
视频详细讲解,需要的小伙伴自行网盘下载,链接见附件,永久有效。 首先,SSM环境中我们通过xml配置的...Springsecurity在两种不同的开发模式中使用,有经典的独立web后台管理系统,也有时下最流行的前后端分离场景。
SpringSecurity框架的权限认证流程原理,请求到来时SpringSecurity如果调用层层过滤器来完成认证;
spring security spring security 中文文档
Spring Security in Action
Spring security 认证-ch02是一个简单安全例子,这个例子在Spring security 认证-ch01中进一步复杂化。下一个例子为Spring security 认证-ch03.请多关注。
很多独立软件供应商,因为灵活的身份验证模式二选择Spring Security。这样做允许他们快速的集成到他们的终端客户需求的解决方案而不用进行大量工程或者改变客户的环境。如果上面的验证机制不符合你的需求,Spring ...
三更springsecurity学习笔记