Spring Security基本原理

近期研究了Spring Security,现进行记录。

首先先进行一个最简单的demo。
默认情况下,在Spring Boot里,如果在classpath下面有Spring Security相关的jar包,那么Spring Boot会自动地替我们做一些安全的配置。本Demo正是基于Spring Boot构建,使用maven进行项目管理。maven核心POM依赖配置如下:

1234567891011121314151617181920212223242526272829303132333435363738394041
<dependencies>

    <dependency>        <groupId>org.springframework.cloud</groupId>        <artifactId>spring-cloud-starter-oauth2</artifactId>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter</artifactId>    </dependency>    <!--Spring Security Web相关-->    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-test</artifactId>        <scope>test</scope>    </dependency></dependencies><dependencyManagement>    <dependencies>        <!--Spring 依赖管理平台-->        <dependency>            <groupId>io.spring.platform</groupId>            <artifactId>platform-bom</artifactId>            <version>Brussels-SR9</version>            <type>pom</type>            <scope>import</scope>        </dependency>        <!--Spring Cloud依赖管理-->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-dependencies</artifactId>            <version>Edgware.SR3</version>            <type>pom</type>            <scope>import</scope>        </dependency>    </dependencies></dependencyManagement>

采用的Spring Boot版本为1.5.12.RELEASE,引入Spring依赖管理平台,最大程度地减少一些依赖的冲突情况,高版本的spring-cloud-starter-oauth2已经包含了Spring Security的依赖,因此引入这一个依赖即可。
然后写一个最简单的demo,只提供一个Rest服务:

1234567891011121314
@RestControllerpublic class  {

    public static void main(String[] args) {        SpringApplication.run(SpringApplicationDemoApplication.class, args);    }

    @GetMapping("/hello")    public String hello(){        return "Hello,Spring Security!";    }

}

然后启动应用,访问http://localhost:8080/hello,发现会弹一个如下的Http Basic认证框,让我们输入用户名和密码。

在不进行任何自定义配置的情况下,Spring Security默认生成的用户名是固定的user,密码的话我们回来看看之前启动Spring Boot时的控制台,可以看到有这么一句话:
Using default security password: fb39f959-fe9c-4d51-abb8-7303cfba4d30

这个就是Spring Security在启动时为我们随机生成的密码。

我们将密码拷贝下来,进行登录,便能够看到我们之前写的那个服务的响应了。

从这个例子里我们可以看到,在默认的情况下,不做任何配置的时候,Spring Security做了这么两件事:

  1. Spring Security将我们所有的服务都保护起来了,任何一个Rest服务,要想调用都要先进行身份认证。
  2. 身份认证的方式就是上图中的http basic的方式,这个是Spring Security默认的一个行为。

但是,这个行为肯定是不能满足我们的需求的,因为没有任何一个应用会用这种Http Basic的方式去做用户的身份校验。
那么,如何覆盖掉Spring Security默认的行为?比如说,提供一个包含用户名和密码的表单登录。我们来看一下,如何处理这样的一个场景。
具体做法是,我们可以编写一个类,继承WebSecurityConfigurerAdapter,这个是Spring Security提供的一个适配器类,从这个名字我们就可以看出来,它是专门做Web安全应用配置的一个适配器,我们在类上写一个@Configuration注解将它声明为一个配置类,并override掉适配器里面的一个configure方法,从源码里我们可以看到有三个configure方法,分别接收三个不同的参数:AuthenticationManagerBuilder,WebSecurity,HttpSecurity。

接收AuthenticationManagerBuilder的方法:

123
protected void configure(AuthenticationManagerBuilder auth) throws Exception {    this.disableLocalConfigureAuthenticationBldr = true;}

接收WebSecurity的方法:

大专栏  Spring Security基本原理">123
public void configure(WebSecurity web) throws Exception {

}

我们重点关注接收参数为HttpSecurity的configure方法,可以看到,它的默认配置正是:

12345678
protected void configure(HttpSecurity http) throws Exception {    http        .authorizeRequests()            .anyRequest().authenticated()            .and()        .formLogin().and()        .httpBasic();}

这段配置翻译过来,正是我们先前的结论:默认情况下Spring Security应用的所有请求都需要经过认证,并且认证方式为Http Basic。
我们现在覆盖掉参数是HttpSecurity的方法,我们想要达到的一个效果是让它用表单的形式登录,那么我们只要像下面这样写:

123456789101112
@Overrideprotected void configure(HttpSecurity http) throws Exception {    //启用基于表单形式的登录    http.formLogin()        .and()        //下面的配置都是关于授权的配置        .authorizeRequests()        //任何请求        .anyRequest()        //都需要认证        .authenticated();}

http.formLogin就是使用基于表单登录进行认证的方式。正如我们一直所强调的,安全其实就是两件事,一个是认证,一个是授权,认证我们已经配置了,但是还不能落下授权。authorizeRequests()开始的就是关于授权的配置。通过五行代码,我们其实就已经定义了一个最简单的安全环境:用表单登录进行身份认证,所有的请求都需要身份认证后才能访问。
定义了这个类之后,我们把系统重新启动,同样访问http://localhost:8080/hello ,这时候我们会发现跳到了如下的一个表单登录页:

在输入了用户名user和从控制台复制过来的随机密码后,我们同样系统在此从登录页跳回了之前的访问的服务,我们也再次看到先前的那个服务的响应。

注意
这里有一个跳转,实际上我们一开始访问这个服务的时候,它给我们跳转到了登录页上,在认证成功后,又再次重定向到我们请求的服务上,这个也是Spring Security默认的登录成功处理器的一个行为。
假设说,我们就是不想使用表单登录,就想使用Http Basic方式进行登录,那么应该怎么写呢?其实也很简单,我们只需要像下面这样写:

123456789101112
@Overrideprotected void configure(HttpSecurity http) throws Exception {    //启用基于Http Basic形式的登录    http.httpBasic()        .and()        //下面的配置都是关于授权的配置        .authorizeRequests()        //任何请求        .anyRequest()        //都需要认证        .authenticated();}

启动应用后,发现又回到之前Http Basic登录认证的方式了。
例子我们暂时先演示到这里,基于这个例子我们已经对Spring Security有了一个基本印象,基于这个印象我们接下来来看看Spring Security的基本原理。

Spring Security基本原理

上图中,最右边这个就是我们的Rest API,也就是我们刚才写的Controller,左边的这组过滤器链正是Spring Security的核心。实际上Spring Security的本质就是一组Filter。因此所有访问服务的请求都会经过Spring Security的过滤器,同样服务器的响应也是会经过这些过滤器然后返回给终端。这些过滤器在系统启动的时候Spring Boot会自动把它配置到上下文上,这个我们暂时先不关注。我们现在主要关注一下这个过滤器链上有哪些过滤器,当然,也是主要的几种过滤器。
首先,最核心的就是上图中绿色的那些过滤器,它的作用是用来认证用户的身份.每一个方块代表一种过滤器,每一种过滤器负责处理一种认证方式。在先前的例子里我们举了两种认证方式:一种是表单登录,一种是Http Basic方式登录,相应地,会有两个类来处理这两种认证请求,也就是上图中的UsernamePasswordAuthenticationFilter(处理表单登录)和BasicAuthenticationFilter(处理HttpBasic登录)。这些绿色的过滤器的主要作用是检查当前的请求里面是不是有这些过滤器所需要的信息.比如说,对UsernamePassword这个过滤器来说,首先它会检查你这个请求是不是一个登录请求,其次它会检查这个登录请求里带没带用户名密码。如果这个登录请求中携带了用户名和密码,这个过滤器就会尝试用这个用户名和密码去进行登录。如果这个请求中没有携带用户名和密码,那么这个过滤器就会把这个请求放行到下一个过滤器。下一个过滤器比如说是BasicAuthenticationFilter,那么这个过滤器就会检查你的请求头里面是不是有Basic开头的这种Authorization信息,如果有的话,它会尝试拿出来做Base64解码,然后取出用户名和密码去尝试进行登录。然后如果我们还有其他的认证方式(其实在Spring Security里它还提供了其他的认证方式),那么按照这个原理它会一个一个往下走,任何一个过滤器它成功地完成了用户的登录之后,它会在请求上做一个标记,告诉后面的过滤器当前的用户已经认证成功了。最终请求经过了绿色的过滤器以后会到一个叫做FilterSecutrityInterceptor的过滤器,这个过滤器是整个Spring Security的最后一环,在这个“守门人”的身后,就是我们自己写的服务了。因此在这个服务里面,它会去决定我们当前的请求能不能去访问后面的服务。那么它依据什么判断呢?就是依据我们代码里的配置。比如说我们先前的配置:所有的请求都要经过身份认证后才能访问,那么它就会去判断当前的请求是不是经过了前面某一个过滤器的身份认证。当然,前面的那个认证配置其实可以配置得很复杂的,比如说某些请求只有管理员才能访问,那么这些规则都会放在FilterSecutrityInterceptor过滤器里面,这个过滤器会根据这些规则去验证。验证的结果也只有两种,如果验证通过的话,那么这个请求就可以访问我们最终的服务了,如果验证不通过,那么根据不通过的原因,它会抛出不同的异常.比如说先前的配置中如果配了所有的请求都要经过身份认证但是实际请求并没有经过认证的话那么它会抛一个身份认证不通过的异常,再比如说先前的配置中如果配置了请求必须要管理员才能访问,那么即使你经过了身份认证但是你不是VIP用户的话那么这个过滤器就会抛一个没权限的异常。总而言之,它会根据不能访问的原因抛出不同的异常。在这个异常抛出来以后,在这个过滤器的前面,还有一个叫做ExceptionTranslationFilter的过滤器,这个过滤器的作用就是用来捕获FilterSecutrityInterceptor所抛出来的异常,然后这个过滤器会根据抛出来的异常做相应的处理,比如说你是因为没有登录所以不能访问,那么它会根据前面那些过滤器的配置引导用户去进行登录.比如说前面我们配置了UsernamePasswordAuthenticationFilter,那么它就会把用户引导到一个登录页面上,比如说我们前面配置了BasicAuthenticationFilter,那么它就会在浏览器上弹一个HttpBasic认证框。这就是Spring Security提供的所有功能和特性都是建立在这个基础之上的。实际上我们工作中一些常见的定制开发比如说增加手机验证码登录,增加第三方QQ微信登录就是在这些绿色的过滤器链上增加不同的过滤器来支持这些不同的认证方式。实际这些程序在运行的时候上面的过滤器肯定不止这三种,一般一个普通的应用一旦运行都会有十几种过滤器,但是目前要想理解Spring Security的基本原理只需要理解这三种过滤器就行了。这里要注意的是,在这个过滤器链上,绿色的部分我们是可以通过配置来决定其是否生效,比如说我们不想用BasicAuthenticationFilter就可以在配置中移除httpBasic的属性,这样BasicAuthenticationFilter就不会生效。但是除了绿色的以外,其他的颜色的过滤器都是不能被我们控制的,它们一定会在过滤器链上并且它们一定会在Spring Security事先指定的位置,比如说这个蓝色的过滤器一定会在橙色的过滤器之前,这个位置我们是不能控制的,我们也不能把它从过滤器上移除。

Spring Security源码初探

l了解完Spring Security的基本原理之后,我们在Spring Security的源码上打一些断点,然后结合上面的图把整个原理再过一下。

原文地址:https://www.cnblogs.com/lijianming180/p/12037903.html

时间: 2024-10-15 18:01:38

Spring Security基本原理的相关文章

Spring Security技术栈开发企业级认证与授权

Spring Security技术栈开发企业级认证与授权网盘地址:https://pan.baidu.com/s/1mj8u6JQ 密码: 92rp备用地址(腾讯微云):https://share.weiyun.com/8b2ffc1839069b4399950333860754a4 密码:a539tn 第1章 课程导学介绍课程内容.课程特点,使用的主要技术栈,以及学习课程所需的前置知识 第2章 开始开发安装开发工具,介绍项目代码结构并搭建,基本的依赖和参数设置,开发hello world 第3

springboot集成spring security实现restful风格的登录认证 附代码

一.文章简介 本文简要介绍了spring security的基本原理和实现,并基于springboot整合了spring security实现了基于数据库管理的用户的登录和登出,登录过程实现了验证码的校验功能. 完整代码地址:https://github.com/Dreamshf/spring-security.git 二.spring security框架简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.主要包括:用户认证

Spring Security入门Demo

一.spring Security简介 SpringSecurity,这是一种基于Spring AOP和Servlet过滤器的安全框架.它提供全面的安全性解决方案,同时在Web请求级和方法调用级处理身份确认和授权.在Spring Framework基础上,Spring Security充分利用了依赖注入(DI,Dependency Injection)和面向切面技术. 二.建立工程 参考http://blog.csdn.net/haishu_zheng/article/details/51490

CAS 与 Spring Security 3整合配置详解

一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分.用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统.用户授权指的是验证某个用户是否有权限执行某个操作.在一个系统中,不同用户所具有的权限是不同的.比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改.一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限. 对于上面提到的两种应用情景,Spring Security 框

spring security+mybatis+springMVC构建一个简单的项目

1.引用 spring security ,这是一种基于spring AOP和Servlet的过滤安全框架.它提供全面的安全性解决方案,同时在web请求级和方法的调用级处理身份确认和授权.在spring framework基础上,spring security充分利用了依赖注入(DI,Dependency Injection)和AOP技术. 下面就让我们用一个小的晓得项目来出初步了解Spring Security 的强大功能吧. 2.项目实战    1)项目的技术架构:maven+spring

Spring Security视频地址

1:Spring Security视频 附件为txt文档内含百度云盘的链接,由于视频太大,所以只能分享链接了..... http://pan.baidu.com/share/link?shareid=2726555995&uk=706734182  提取码:60tb 2:Spring Securoty: 链接:http://pan.baidu.com/s/1o6x2sye 密码:fi2x 3:链接: http://pan.baidu.com/s/1pJnylQF 密码: wj6b 4:http:

spring security oauth2 jwt 认证和资源分离的配置文件(java类配置版)

最近再学习spring security oauth2.下载了官方的例子sparklr2和tonr2进行学习.但是例子里包含的东西太多,不知道最简单最主要的配置有哪些.所以决定自己尝试搭建简单版本的例子.学习的过程中搭建了认证和资源在一个工程的例子,将token存储在数据库的例子等等 .最后做了这个认证和资源分离的jwt tokens版本.网上找了一些可用的代码然后做了一个整理, 同时测试了哪些代码是必须的.可能仍有一些不必要的代码在,欢迎大家赐教. 一.创建三个spring boot 工程,分

springsecurity启动出现org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: You must use a 3.0 schema with Spring Security 3.0.

在换了spring-security的jar包以后启动出现org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: You must use a 3.0 schema with Spring Security 3.0.Please update your schema declarations to the 3.0.3 schema (spring-securi

REST Security with JWT using Java and Spring Security

Security Security is the enemy of convenience, and vice versa. This statement is true for any system, virtual or real, from the physical house entrance to web banking platforms. Engineers are constantly trying to find the right balance for the given