介绍:什么是oAuth :oauth是一个协议,是为用户资源的授权提供一个安全的,开放而又简易的标准,与以往的授权方式不同之处是,oauth的授权不会使第三方接触到到第三方的账号信息,即第三方无需使用用户的用户名与密码就可以申请获得该用户的资源的授权,因此oauth 是安全的。
什么是Security:Spring Security 是一个安全框架,能够为Spring企业应用系统提供声明式的安全访问控制,Spring Security基于Servlet过滤器,Ioc和Aop,为Web请求和方法的调用提供身份确认和授权处理,避免了代码的耦合,减少了大量的重复代码。
交互过程:
oauth 在客户端 与服务提供商之间,设置了一个授权层,客户端是不能直接登录 服务提供商的,只能登录授权层,从此将用户与客户端分来,客户端登录登录授权层所用的令牌(Token),与用户的密码不同,用户可以在登录的时候,指定授权层令牌的权限范围和有效期,客户端 登录授权层之后,服务提供商会根据令牌的权限范围和有效期,想客户端 开放用户存储的资料。
从上图我们可以看出,在交互模型涉及的共有三方
资源拥有者:用户
客户端:App、浏览器等。。
服务提供方:
认证服务器
资源服务器
什么是认证服务器:
认证服务器负责对用户进行认证,并授权给客户端权限,认证很容易(验证账户和密码即可),问题在于如何授权,比如当我们使用第三方登陆时,比如qq,会直接跳转到qq的登录页面,同时会有 授权 的字样
认证服务器在认证的时候,需要知道 请求授权 的客户端的身份以及该客户端的请求的权限,我们可以为每一个客户端预先分配一个id,并给每个id对应一个名称以及权限的信息,这些信息可以写在认证服务器上的配置文件中,然后,客户端每次打开授权页面的时候,把属于自己的id传递过来,如下:
http://localhost:8080/login?client_id=yourClientId
但是随着时间的推移和业务的增长,会发现,修改配置的工作消耗太多的人力。
oAuth2开放平台
开放平台是由oAuth2.0 协议衍生出的一个产品,他的作用就是让客户端自己去这面去注册、申请、通过之后系统自动分配client_id ,并完成配置的自动更新(通常是写进数据库)。客户端要完成申请,通常需要填写客户端程序的类型(Web。app等)、企业介绍,执照,想要获取的权限等信息,这些信息在得到服务提供方的人工审核通过之后,开放平台会自动分配一个client_id给客户端。
到这里就实现登录认证,授权页的信息展示,那么接下来,当用户进行授权之后,认证服务器需要把产生的access_token 发送给客户端,方案如下;
让客户端开放平台申请的时候,填写一个URL,例如:http://localhost:8080/
每次当用户授权成功之后,认证服务器将页面重定向到 这个URL(回调),并带上access_token,例如:http://localhost:8080?access_token=123123
客户端接受到了这个 access_token 而且认证服务器的授权动作已经完成,刚好把程序的控制权交给客户端,由客户端决定接下来向用户展示什么内容。
下面讲解什么时候 Access Token :
Access Token 是客户端访问资源服务器的令牌,拥有这个令牌代表得到用户的授权,然而这个令牌是临时的,有一定的有效期,这是因为 Access Token 在使用过程会可能泄露,给Access token 限定一个较短的 有效期,可以降低因Access Token 泄露带来的风险。
但是在这样引入有效期之后,客户端使用起来就不方便,每当Access Token 过期,客户端就必须重新向用户索要授权,于是oAuth2.0引入了 Refresh token 的机制
Refresh Token
Refresh Token 的作用是用用来刷新Access token 的,认证服务器提供一个刷新的接口,
http://localhost:8080/refresh?refresh_token=&client_id=
传入 refresh_token 和 client_id ,认证服务器验证通过之后,返回一个新的Access Token 为了安全,oAuth2引入了两个措施:
oAuth2.0 要求,Refresh Token 一定 保存在客户端的服务器上, 而觉不能存放在客户端(app 、pc端软件)上,调用refresh 接口的时候,一定是从 服务器到服务器的访问。
oauth2.0 引入了 client_secret 机制,即每一个 clieng_id 都对应一个clieng_secret ,这个clieng_secret 机制,即每一个clieng_id 都对应一个clieng_secret 一起分配给客户端,客户端 必须把 clieng_secret 妥善保存在服务器上,决不能泄露,在刷新Access Token时,需要验证这个client_secret.
http://localhost:8080/refresh?refresh_token=&client_id=&client_secret=
这就是 Refresh Token 的机制,Refresh Token 的有效期非常长,会在用户授权时,随Access Token 一起重定向到回调URL 传递给客户端
下面讲解什么是授权模式:
客户端在必须得到用户的授权(authorization grant),才能获取到令牌(access token)。oAuth2定义了四种授权方式
implicit : 简化模式,不推荐使用
authorization code : 授权码模式
resource owner password credentials : 密码模式
client credentals : 客户端模式
简化模式:
简化模式适合用于纯静态页面的应用,所谓纯静态页面的应用,也就是应用没有在服务器上执行代码的权限(通常就是吧代码托管到别人服务器上),只有前端js 代码的控制权,相当于只有h5 客户端,没有后台,使用该模式,该模式中的Access Token 容易泄露,且不可刷新
授权码模式:
授权码模式适用于自己的服务器i的应用,他是一个一次性的临时凭证,用来换取access_token 和 refresh_token 认证服务器提供了一个类似这样的接口,。
https://localhost:8080/exchange?code=&client_id=&client_secret=
需要传入 code 、client_id 以及 client_secret 验证通过之后,返回Access_token 和 refresh_token ,一旦换取成功,code 立即作废,不能在使用第二次。
这个code 的作用是保护Token 的安全性,简单模式不安全的原因是,在第四步重定向将token返回给应用的时候,这一步容易v被拦截,但是在引入code 之后,即使获取到code,但是由于无法获取保存在服务器的client_secret ,因为也无法通过code 换取token,在第五步,是服务器与服务器之间的访问,所以不容易拦截,其次,这个请求通常是https的实现,即使能监听到数据包也无法解析出内容。
使用场景: 不对外提供账户和密码,自己使用账户和密码
所以说有了这个code,token的安全性大大的提高,因此,oAuth2.0 鼓励使用这种方式进行授权。
密码模式:
在密码模式中,用户向客户端提供自己的用户名和密码,客户端使用这些信息,想 服务商提供商所要授权,在这种模式下,用户必须把自己的密码给客户端,但是客户端不存储密码,这通常用在对客户端高度信任的情况下,比如客户端是操作系统的一部分。
该模式的使用场景:一个公司的两个系统,登录一个系统的时候同时登录另外一个系统
在使用的时候,第2步中,认证服务器需要对客户端的身份进行验证,确保是受信任的客户端
客户端模式:
两个客户端公用一个后端的模块,没有用户界面的时候,可以用户客户端模式
下面的代码是一个简单的小案例,可以对Tocken 的刷新,获取,然后访问静态资源数据,但是这些并没有真正的与qq等第三方对接,后续的代码还在更新中....
首选查看我的项目的结构:
首先是spring-security-oauth2 的 pom文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.funtl</groupId>
<artifactId>spring-security-oathou2</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<url>http://www.funtl.com</url>
<modules>
<module>spring-security-oauth2-dependencies</module>
<module>spring-security-oauth2-server</module>
<module>spring-security-oauth2-resource</module>
</modules>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<licenses>
<license>
<name>Apache 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.funtl</groupId>
<artifactId>spring-security-oauth2-dependencies</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<spring-javaformat.version>0.0.7</spring-javaformat.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
<version>${spring-javaformat.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/Abstract*.java</exclude>
</excludes>
<systemPropertyVariables>
<java.security.egd>file:/dev/./urandom</java.security.egd>
<java.awt.headless>true</java.awt.headless>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-rules</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<excludes>
<exclude>commons-logging:*:*</exclude>
</excludes>
<searchTransitive>true</searchTransitive>
</bannedDependencies>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
<inherited>true</inherited>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Milestone</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshot</id>
<name>Spring Snapshot</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestone</id>
<name>Spring Milestone</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshot</id>
<name>Spring Snapshot</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
总的一个依赖的管理是 spring-security-oauth2-dependencies 项目
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.funtl</groupId>
<artifactId>spring-security-oauth2-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<url>http://www.funtl.com</url>
<properties>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<spring-boot-mapper.version>2.1.5</spring-boot-mapper.version>
</properties>
<licenses>
<license>
<name>Apache 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>${hikaricp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<!-- 排除 tomcat-jdbc 以使用 HikariCP -->
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${spring-boot-mapper.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Milestone</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshot</id>
<name>Spring Snapshot</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestone</id>
<name>Spring Milestone</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshot</id>
<name>Spring Snapshot</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
待续。。