zhangdaiscott 发表于 2024-3-7 12:00:50

旧的Spring Security OAuth已停止维护,全面拥抱新解决方案Sprin...

## Spring Authorization Server 替换 Shiro 指引

## 背景

* Spring 团队正式宣布 **Spring Security OAuth 停止维护**,该项目将不会再进行任何的迭代
![](https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/add16777945e44059c3d13453b474983~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1709863235&x-signature=ueW3VHp6%2FoFQOYhUtYuxgYzt%2F%2F0%3D)

* 目前 Spring 生态中的 OAuth2 授权服务器是 **Spring Authorization Server** 已经可以**正式生产使用**
* 作为 SpringBoot 3.0 的最新权限方案,JeecgBoot springboot3_sas分支,已经完成了采用Spring Authorization Server 替换 Shiro工作。

## JeecgBoot SAS分支

> - Date: 2024-01-17
> - 技术栈: SpringBoot3+ Spring Authorization Server+jdk18

源码下载:

- 后端:[https://github.com/jeecgboot/jeecg-boot/tree/springboot3_sas](https://github.com/jeecgboot/jeecg-boot/tree/springboot3_sas)
- 前端:[https://github.com/jeecgboot/jeecgboot-vue3/tree/springboot3_sas](https://github.com/jeecgboot/jeecgboot-vue3/tree/springboot3_sas)

### 登录对接

> jeecg 基于Spring Authorization Server扩展了四种登录实现,加上默认提供的四种,共计有8种登录方式,额外还有OpenID Connect模式。本文不讲解授权码模式、客户端模式、刷新码模式、设备码模式、OpenID Connect模式,只会讲解jeecg实际应用了的四种扩展模式,其它模式请查阅Spring Authorization Server官方原文。
>
> https://docs.spring.io/spring-authorization-server/reference/overview.html
>
> 注意:OpenID Connect应当仅为认证阶段使用,不可作为权限校验阶段使用。

#### 密码模式和APP模式

> 密码模式在Oauth2.1协议中被放弃,Spring Authorization Server并没有对该模式提供实现,该实现是基于Spring Authorization Server提供的扩展入口实现的。
>
> 密码模式实现源码:package org.jeecg.config.security.password;
>
> APP模式实现源码:package org.jeecg.config.security.app;
>
> 密码模式与APP模式实现完全一致,不过防止额外需求偏差,所以进行了分开实现。

请求地址:{baseUrl} /oauth2/token

请求方法:POST

请求头:

| 请求头名称    | 请求头值                                              |
| ------------- | ----------------------------------------------------- |
| Authorization | Basic base64(clientId\:clientSecret)(此处需要自行替换) |
| Content-Type| application/x-www-form-urlencoded                     |

请求参数:

| 参数名称   | 参数值                                             |
| ---------- | -------------------------------------------------- |
| grant_type | password/app (password为PC端使用,app为移动端使用) |
| username   | 用户名                                             |
| password   | 密码                                             |

响应内容:

| 参数名称      | 参数含义                                                   |
| ------------- | ------------------------------------------------------------ |
| access_token| 访问token,在被限制访问的接口请求中添加Authorization: Bearer access_token |
| refersh_token | 刷新token,用于刷新码模式获取新的access_token                |
| userInfo      | 当前登录用户信息                                             |
| ...         | 其它内容不作详解,请查看源码                                 |

#### phone模式

> phone模式用于手机+验证码登录场景。
>
> phone模式实现源码:package org.jeecg.config.security.phone;

请求地址:{baseUrl} /oauth2/token

请求方法:POST

请求头:

| 请求头名称    | 请求头值                                              |
| ------------- | ----------------------------------------------------- |
| Authorization | Basic base64(clientId\:clientSecret)(此处需要自行替换) |
| Content-Type| application/x-www-form-urlencoded                     |

请求参数:

| 参数名称   | 参数值      |
| ---------- | ----------- |
| grant_type | 固定为phone |
| mobile   | 手机号      |
| captcha    | 验证码      |

响应内容:

| 参数名称      | 参数含义                                                   |
| ------------- | ------------------------------------------------------------ |
| access_token| 访问token,在被限制访问的接口请求中添加Authorization: Bearer access_token |
| refersh_token | 刷新token,用于刷新码模式获取新的access_token                |
| userInfo      | 当前登录用户信息                                             |
| ...         | 其它内容不作详解,请查看源码                                 |

#### social模式

> 任何一个用户中心端(比如微信、微博、github、gitee)对外提供的对接方式都是授权码模式、OpenID Connect模式,最终获取到一段用户信息(比如用户名、头像地址、邮箱),但是其实并没有办法拿着这段信息在当前系统中访问受限资源,以前都是手搓token或者其它手段来得到受限访问的权限,这种方法不可靠也不安全,而且也不易维护。
>
> jeecg针对以上场景,基于Spring Authorization Server扩展了social模式,用于处理获取三方用户信息后,再获取当前系统的访问凭证。
>
> social模式实现源码:package org.jeecg.config.security.social;
>
> 提示:文档中只讲解social模式的应用,不讲解从三方登录到应用social模式的全流程,jeecg前后端均已实现,细节请查看源码。

请求地址:{baseUrl} /oauth2/token

请求方法:POST

请求头:

| 请求头名称    | 请求头值                                              |
| ------------- | ----------------------------------------------------- |
| Authorization | Basic base64(clientId\:clientSecret)(此处需要自行替换) |
| Content-Type| application/x-www-form-urlencoded                     |

请求参数:

| 参数名称   | 参数值               |
| ---------- | -------------------- |
| grant_type | 固定为social         |
| token      | 可获取用户信息的凭证 |
| thirdType| 三方来源             |

响应内容:

| 参数名称      | 参数含义                                                   |
| ------------- | ------------------------------------------------------------ |
| access_token| 访问token,在被限制访问的接口请求中添加Authorization: Bearer access_token |
| refersh_token | 刷新token,用于刷新码模式获取新的access_token                |
| userInfo      | 当前登录用户信息                                             |
| ...         | 其它内容不作详解,请查看源码                                 |

### 权限校验

可用于方法或类上,将基于注解的权限code,针对性处理方法或当前类的所有接口进行权限拦截。

#### 基于角色

~~~java
// shiro用法
@RequiresRoles("admin")

// 可替换为 spring authorization server 用法
@PreAuthorize("jps.requiresRoles('admin')")
~~~

#### 基于权限

~~~java
// shiro用法
@RequiresPermissions("sys:role")


// 可替换为 spring authorization server 用法
@PreAuthorize("jps.requiresPermissions('sys:role')")
~~~

角色和权限组合使用

~~~java
- @PreAuthorize("@jps.requiresPermissions('system:quartzJob:add') or @jps.requiresRoles('admin')")
~~~

#### 免登录配置

~~~yaml
jeecg:
shiro:
    excludeUrls: /test/jeecgDemo/demo3,/test/jeecgDemo/redisDemo/**,/jmreport/bigscreen2/**




# 替换为
security:
oauth2:
    client:
      ignore-urls:
      - /test/jeecgDemo/demo3
      - /test/jeecgDemo/redisDemo/**
      - /jmreport/bigscreen2/**
~~~

### 升级小技巧

| 搜索                                                | 替换为                                                   |
| ----------------------------------------------------- | -------------------------------------------------------- |
| org.apache.shiro.SecurityUtils                        | org.jeecg.config.security.utils.SecureUtil               |
| (LoginUser) SecurityUtils.getSubject().getPrincipal() | SecureUtil.currentUser()                                 |
| org.apache.shiro.authz.annotation.RequiresRoles       | org.springframework.security.access.prepost.PreAuthorize |
| org.apache.shiro.authz.annotation.RequiresPermissions | org.springframework.security.access.prepost.PreAuthorize |
| @RequiresPermissions                                  | @PreAuthorize("jps.requiresPermissions('xxx')")          |
| @RequiresRoles                                        | @PreAuthorize("@jps.requiresRoles('xxx')")

### 升级SQL

切换springboot3_sas分支的Spring Authorization Server,需要执行升级sql

```
CREATE TABLE `oauth2_registered_client` (
`id` varchar(100) NOT NULL,
`client_id` varchar(100) NOT NULL,
`client_id_issued_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`client_secret` varchar(200) DEFAULT NULL,
`client_secret_expires_at` timestamp NULL DEFAULT NULL,
`client_name` varchar(200) NOT NULL,
`client_authentication_methods` varchar(1000) NOT NULL,
`authorization_grant_types` varchar(1000) NOT NULL,
`redirect_uris` varchar(1000) DEFAULT NULL,
`post_logout_redirect_uris` varchar(1000) DEFAULT NULL,
`scopes` varchar(1000) NOT NULL,
`client_settings` varchar(2000) NOT NULL,
`token_settings` varchar(2000) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;


INSERT INTO `oauth2_registered_client`
(`id`,
`client_id`,
`client_id_issued_at`,
`client_secret`,
`client_secret_expires_at`,
`client_name`,
`client_authentication_methods`,
`authorization_grant_types`,
`redirect_uris`,
`post_logout_redirect_uris`,
`scopes`,
`client_settings`,
`token_settings`)
VALUES
('3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
'jeecg-client',
now(),
'secret',
null,
'3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
'client_secret_basic',
'refresh_token,authorization_code,password,app,phone,social',
'http://127.0.0.1:8080/jeecg-',
'http://127.0.0.1:8080/',
'*',
'{"@class":"java.util.Collections$UnmodifiableMap","settings.client.require-proof-key":false,"settings.client.require-authorization-consent":true}',
'{"@class":"java.util.Collections$UnmodifiableMap","settings.token.reuse-refresh-tokens":true,"settings.token.id-token-signature-algorithm":["org.springframework.security.oauth2.jose.jws.SignatureAlgorithm","RS256"],"settings.token.access-token-time-to-live":["java.time.Duration",300000.000000000],"settings.token.access-token-format":{"@class":"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat","value":"self-contained"},"settings.token.refresh-token-time-to-live":["java.time.Duration",3600.000000000],"settings.token.authorization-code-time-to-live":["java.time.Duration",300000.000000000],"settings.token.device-code-time-to-live":["java.time.Duration",300000.000000000]}');
```

### 常用API

#### 1. 获取登录用户信息

LoginUser sysUser = SecureUtil.currentUser();



页: [1]
查看完整版本: 旧的Spring Security OAuth已停止维护,全面拥抱新解决方案Sprin...