Spring Security基本原理(Spring Boot1.x版本适用,2.x部分配置参数会变)

在SpringBoot开发时,通常都会对URI资源进行访问保护,就会引入如下starter模块:

这里暂时还没在yml文件配置auth服务的参数,因为这个oauth2的pom.xml文件里面也包含了spring security,所以可以直接使用:

如果不用Spring cloud,只用Spring boot,也可以直接引用,上面最终也是引用下面的依赖的:

spring boot的security-starter模块在引入后,没做任何配置的话,会对所有接口进行保护,因此,在访问的时候,会弹出登录框:

在spring启动时在日志中会输出一个默认的用户user的密码:

输入Username(默认: user)和Password即可正常登录访问。

我们可以在application.yml配置自己的用户名和密码:

默认的安全机制肯定不普遍适用,可以继承WebSecurityConfigurerAdapter来配置,然后重写configure方法来自定义验证处理逻辑:

前面的跳出登录窗口的处理其实默认的实现就是configure(HttpSecurity),如下:

下面来自定义实现一下:

这样,在访问”/test”或”/login”接口就不需要验证直接访问,其他就需要登录了。我们还可以指定自己的登录页面,登录成功的处理器或登录失败的处理器等,如继承该类可以实现自己的登录成功处理逻辑AbstractAuthenticationFilterConfigurer.java

如果需要配合自己业务系统的用户的用户进行验证,实现这个接口org.springframework.security.core.userdetails.UserDetailsService即可:

更多函数可以参考源码,进行测试调用即可。

大致使用了Spring Security后,不难理解,Spring Security其实就是很完善的过滤器链,在spring boot启动时初始化所有过滤器,然后用户的请求的服务的响应都会经过过滤器,类似我们在路由里面实现的ZuulFilter:

每个过滤器按照优先级进行逐级过滤,spring security的过滤器有用户名和密码验证org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.java、第三方登录验证等过滤器,默认是基于用户名和密码的,在过滤器里,当收到用户请求后,就会判断请求是否有过滤器需要的验证信息,有就用对应的过滤器进行验证。所有的过滤器都是继承于抽象基类GenericFilterBean的,可以看到目前有如下几种过滤器的实现:

经过层层过滤器的验证后,最后会来到org.springframework.security.web.access.intercept.FilterSecurityInterceptor.java这个过滤器,这个类会检查经过前面验证过滤器的请求是否能访问后面的接口,可以则放行,否则,抛出无权限异常,会被org.springframework.security.web.access.ExceptionTranslationFilter类捕获:

整个过滤器链流程如下所示:

这个过程可以自己在相应类下断点调试看看流程是否真的这样执行。有了前面的几个过滤器,那么,整个认证过程流程,大致涉及如下几个核心类串起来的:

应用启动后,不是所有过滤器都会生效的,spring boot会根据我们的配置,如我们前面配置了formLogin()这个过滤器,那么这个过滤器就生效而其他过滤器不生效,但是,在上面过滤器链中,绿色的才是可配置是否生效的,其他颜色的,一定会在过滤器链中。

前面我们配置了用户名密码登录,在登录界面点击了”登录”按钮后,我们首先会进入这个org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.java过滤器:

获取了用户信息后,开始进行校验处理org.springframework.security.authentication.ProviderManager.java

这里用for循环去执行验证器,这里用户名和密码的验证器为如下:

认证成功后,会在org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter类的successfulAuthentication方法把当前登录用户信息写到session里:

因为一次请求和响应在一个线程中处理,所以,把当前请求的认证信息放到SecurityContextHolder里,它是ThreadLocal的,因此,所以可以在任何地方获取到当前登录用户的信息。
请求进来,会先进入到这个过滤器:

它会进行请求和响应信息的session处理,这样,用户登录后,在进行其他请求时,都能获得登录用户的信息。

今天踩坑了,不得不好好了解下Spring Security,大致流程就这样,后面有时间再补充缺少的理解吧。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 linjk121@163.com.