官方文档:
OAuth2 :: Spring Security

概念

OAuth是一个开放标准,也就是一个授权框架,使应用程序能够访问其它公司提供的资源,允许用户在第三方应用访问存储在其他服务器上的私密资源,而在整个过程不需要提供用户名和密码给到第三方应用,可以通过提供一个令牌(token)实现该功能,采用令牌的方式可以让用户灵活的对第三方应用授权或收回权限。

OAuth2 四种角色

Oauth一共定义了四种角色:

  1. 资源所有者(Resource Owner):即代表用户本身
  2. 资源服务器(Resource Server) :存储受保护的账号信息
  3. 授权服务器(Authorization Server):在成功验证用户身份,并获得授权后,给客户端派发访问资源令牌
  4. 客户端(Client):即代表你访问的第三方应用

OAuth2的四种模式

参考文章:
【OAuth2】详细讲解-CSDN博客

授权码模式

image.png

简化模式

image.png

密码模式

image.png

客户端模式

image.png

Springboot 集成

示例代码:
https://github.com/spring-projects/spring-security-samples/tree/6.2.x/servlet/spring-boot/java/oauth2

认证服务器配置

参考文章:
Spring Security OAuth2的基本使用_security.oauth2.client-CSDN博客
1、导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

注意 springboot 版本和 jdk 版本也会导致项目启动不起来,可以将 springboot 2.2.8.RELEASE 版本,用 jdk 8 测试
2、在 conf 配置类添加上 @EnableAuthorizationServer 注解,使 oauth2 能够自动装配,这个注解配置的认证服务器(将该项目定义为认证服务器),security 的配置就直接看这个
image.png
3、修改配置文件

security:
  oauth2:
    client:
      client-id: web
      client-secret: 123456789
      registered-redirect-uri: http://127.0.0.1:8080/hello

4、启动项目,因为添加了 @EnableAuthorizationServer 注解,所以会自动配置 oauth 的信息
image.png
5、访问链接获取 token
http://localhost:8080/oauth/authorize?response_type=code&client_id=web&redirect_uri=http://127.0.0.1:8080/hello&scope=all

response_type=code:表示授权码模式
client_id=web:配置文件中指定的web
redirect_uri:指定一个地址,用来重定向获取授权码,这个地址必须存在配置文件中,否则无效
scope=all:表示所有权限

image.png
登录成功之后会让用户进行授权,选择 Approve 然后授权
image.png
则会跳转到指定的链接,并携带上 code 凭证
image.png
6、根据凭证获取 token

请求地址:http://127.0.0.1:8080/oauth/token

header:
Authorization: Basic [client_id:client_secret]的base64加密

body:
grant_type:authorization_code    # 凭证模式
code:授权码
client_id:web
redirect_uri:http://127.0.0.1:8080/hello
scope:all

请求头需要使用 client_id 和 client_secret 的 base64 编码,可以使用 base64在线编码 网站进行编码
image.png
image.png
7、此时获取得到的 token 还无法直接访问资源,还需要配置资源服务器之后才能进行访问

密码模式获取 token

1、直接发起认证请求即可获取 token

请求地址:http://127.0.0.1:8080/oauth/token

header:
Authorization: Basic [client_id:client_secret]的base64加密

body:
grant_type:password        # 密码模式
username: admin                # 使用 security 的账号密码
password: admin123
scope:all

image.png

资源服务器配置

1、导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2、修改配置文件

security:
  oauth2:
    client:
      clientId: clientId
      clientSecret: 123456
      accessTokenUri: http://localhost:8080/auth/token
      userAuthorizationUri: http://localhost:8080/auth/authorize

3、在配置文件添加注解

@EnableResourceServer

这样应该就完成了

源码分析

认证服务

image.png
而在 EnableAuthorizationServer 注解中导入了两个配置类
image.png
其中的 AuthorizationServerSecurityConfiguration 配置类继承了 WebSecurityConfigurerAdapter 类,相当于覆盖了 security 的默认配置类,这一步跟我们配置
image.png
重写 security 的 configure 方法,对请求进行配置,其中的配置类 configurers 是通过依赖注入的方式引用的
image.png
image.png
image.png
所以在 oauth2 认证服务项目中,我们可以通过自定义 AuthorizationServerConfigurer 实现类的 bean,即可对 security 的认证流程进行配置
image.png
例如

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { 
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) { 
        security.allowFormAuthenticationForClients().tokenKeyAccess("permitAll()").checkTokenAccess("permitAll()");
    } 
} 

配置类说明:
image.png
ClientDetailsServiceConfigurer:用来配置客户端详情服务,看支持哪些客户端来请求
AuthorizationServerEndpointsConfigurer:解决两点:客户端来申请令牌了,申请的地址是什么(令牌端点)以及令牌怎么发放
AuthorizationServerSecurityConfigurer:配置令牌端点的安全约束,哪些url开放,哪些需要鉴权

资源服务

导入 @EnableResourceServer 注解之后就会导入 ResourceServerSecurityConfigurer 配置文件
image.png
image.png
而这个配置文件会添加一个 过滤器,并指定一个 AuthenticationManager 实现类 OAuth2AuthenticationManager
image.png
image.png
image.png
所以当请求资源服务器的时候就会经过 过滤器,从而调用 OAuth2AuthenticationManager 的 authenticate() 方法进行鉴权并获取用户信息
image.png
image.png
而这里的 tokenService 默认是使用 UserInfoTokenServices 这个类型的 bean
image.png
因为当我们没配置的时候会自动创建这个 bean
image.png
UserInfoTokenServices 就会再根据配置的路径信息和 token 去获取用户信息
image.png
而这里用到的 restTemplate 是 OAuth2RestTemplate 类型的
image.png

自定义登录接口

在 oauth2 代码中,默认是直接使用 TokenEndpoint 类的 postAccessToken 方法进行密码模式的登录功能
image.png

jwt 的使用