2021-07-19 01:12:55 +08:00
|
|
|
# 搭建OAuth2-Server
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### 1、准备工作
|
|
|
|
|
首先修改hosts文件`(C:\windows\system32\drivers\etc\hosts)`,添加以下IP映射,方便我们进行测试:
|
|
|
|
|
``` url
|
|
|
|
|
127.0.0.1 sa-oauth-server.com
|
|
|
|
|
127.0.0.1 sa-oauth-client.com
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 2、引入依赖
|
2024-08-19 17:49:59 +08:00
|
|
|
创建SpringBoot项目 `sa-token-demo-oauth2-server`(不会的同学自行百度或参考仓库示例),引入 `pom.xml` 依赖:
|
2021-07-19 01:12:55 +08:00
|
|
|
|
2022-10-20 13:06:36 +08:00
|
|
|
<!---------------------------- tabs:start ---------------------------->
|
|
|
|
|
<!-------- tab:Maven 方式 -------->
|
2021-07-19 01:12:55 +08:00
|
|
|
``` xml
|
2022-10-21 11:27:29 +08:00
|
|
|
<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc -->
|
2021-07-19 01:12:55 +08:00
|
|
|
<dependency>
|
|
|
|
|
<groupId>cn.dev33</groupId>
|
|
|
|
|
<artifactId>sa-token-spring-boot-starter</artifactId>
|
|
|
|
|
<version>${sa.top.version}</version>
|
|
|
|
|
</dependency>
|
|
|
|
|
|
|
|
|
|
<!-- Sa-Token-OAuth2.0 模块 -->
|
|
|
|
|
<dependency>
|
|
|
|
|
<groupId>cn.dev33</groupId>
|
|
|
|
|
<artifactId>sa-token-oauth2</artifactId>
|
|
|
|
|
<version>${sa.top.version}</version>
|
|
|
|
|
</dependency>
|
|
|
|
|
```
|
2022-10-20 13:06:36 +08:00
|
|
|
<!-------- tab:Gradle 方式 -------->
|
|
|
|
|
``` gradle
|
2022-10-21 11:27:29 +08:00
|
|
|
// Sa-Token 权限认证,在线文档:https://sa-token.cc
|
2022-10-20 13:06:36 +08:00
|
|
|
implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'
|
|
|
|
|
|
|
|
|
|
// Sa-Token-OAuth2.0 模块
|
|
|
|
|
implementation 'cn.dev33:sa-token-oauth2:${sa.top.version}'
|
|
|
|
|
```
|
|
|
|
|
<!---------------------------- tabs:end ---------------------------->
|
|
|
|
|
|
|
|
|
|
|
2021-07-19 01:12:55 +08:00
|
|
|
|
|
|
|
|
### 3、开放服务
|
2024-08-19 17:49:59 +08:00
|
|
|
1、自定义数据加载器:新建 `SaOAuth2DataLoaderImpl` 实现 `SaOAuth2DataLoader` 接口。
|
|
|
|
|
|
2021-07-19 01:12:55 +08:00
|
|
|
``` java
|
|
|
|
|
/**
|
2024-08-19 17:49:59 +08:00
|
|
|
* Sa-Token OAuth2:自定义数据加载器
|
2021-07-19 01:12:55 +08:00
|
|
|
*/
|
|
|
|
|
@Component
|
2024-08-19 17:49:59 +08:00
|
|
|
public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
|
2021-07-19 01:12:55 +08:00
|
|
|
|
2024-08-19 17:49:59 +08:00
|
|
|
// 根据 clientId 获取 Client 信息
|
2021-07-19 01:12:55 +08:00
|
|
|
@Override
|
|
|
|
|
public SaClientModel getClientModel(String clientId) {
|
|
|
|
|
// 此为模拟数据,真实环境需要从数据库查询
|
|
|
|
|
if("1001".equals(clientId)) {
|
|
|
|
|
return new SaClientModel()
|
2024-08-19 17:49:59 +08:00
|
|
|
.setClientId("1001") // client id
|
|
|
|
|
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee") // client 秘钥
|
|
|
|
|
.addAllowUrls("*") // 所有允许授权的 url
|
|
|
|
|
.addContractScopes("openid", "userid", "userinfo") // 所有签约的权限
|
|
|
|
|
.setIsAutoMode(true); // 是否自动判断开放的授权模式
|
2021-07-19 01:12:55 +08:00
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-19 17:49:59 +08:00
|
|
|
// 根据 clientId 和 loginId 获取 openid
|
2021-07-19 01:12:55 +08:00
|
|
|
@Override
|
|
|
|
|
public String getOpenid(String clientId, Object loginId) {
|
2024-08-19 17:49:59 +08:00
|
|
|
// 此处使用框架默认算法生成 openid,真实环境建议改为从数据库查询
|
|
|
|
|
return SaOAuth2DataLoader.super.getOpenid(clientId, loginId);
|
2021-07-19 01:12:55 +08:00
|
|
|
}
|
2024-08-19 17:49:59 +08:00
|
|
|
|
2021-07-19 01:12:55 +08:00
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-08 16:05:54 +08:00
|
|
|
你可以在 [框架配置](/use/config?id=SaClientModel属性定义) 了解有关 `SaClientModel` 对象所有属性的详细定义
|
|
|
|
|
|
|
|
|
|
|
2021-07-19 01:12:55 +08:00
|
|
|
2、新建`SaOAuth2ServerController`
|
|
|
|
|
``` java
|
|
|
|
|
/**
|
|
|
|
|
* Sa-OAuth2 Server端 控制器
|
|
|
|
|
*/
|
|
|
|
|
@RestController
|
|
|
|
|
public class SaOAuth2ServerController {
|
|
|
|
|
|
|
|
|
|
// 处理所有OAuth相关请求
|
|
|
|
|
@RequestMapping("/oauth2/*")
|
|
|
|
|
public Object request() {
|
|
|
|
|
System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl());
|
|
|
|
|
return SaOAuth2Handle.serverRequest();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sa-OAuth2 定制化配置
|
|
|
|
|
@Autowired
|
|
|
|
|
public void setSaOAuth2Config(SaOAuth2Config cfg) {
|
2024-08-19 17:49:59 +08:00
|
|
|
|
|
|
|
|
// 配置:未登录时返回的View
|
|
|
|
|
cfg.notLoginView = () -> {
|
|
|
|
|
String msg = "当前会话在OAuth-Server端尚未登录,请先访问"
|
|
|
|
|
+ "<a href='/oauth2/doLogin?name=sa&pwd=123456' target='_blank'> doLogin登录 </a>"
|
|
|
|
|
+ "进行登录之后,刷新页面开始授权";
|
|
|
|
|
return msg;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 配置:登录处理函数
|
|
|
|
|
cfg.doLoginHandle = (name, pwd) -> {
|
|
|
|
|
if("sa".equals(name) && "123456".equals(pwd)) {
|
|
|
|
|
StpUtil.login(10001);
|
|
|
|
|
return SaResult.ok();
|
|
|
|
|
}
|
|
|
|
|
return SaResult.error("账号名或密码错误");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 配置:确认授权时返回的 view
|
|
|
|
|
cfg.confirmView = (clientId, scopes) -> {
|
|
|
|
|
String scopeStr = SaFoxUtil.convertListToString(scopes);
|
|
|
|
|
String msg = "<p>应用 " + clientId + " 请求授权:" + scopeStr + "</p>"
|
|
|
|
|
+ "<p>请确认:<a href='/oauth2/doConfirm?client_id=" + clientId + "&scope=" + scopeStr + "' target='_blank'> 确认授权 </a></p>"
|
|
|
|
|
+ "<p>确认之后刷新页面</p>";
|
|
|
|
|
return msg;
|
|
|
|
|
};
|
2021-07-19 01:12:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 全局异常拦截
|
|
|
|
|
@ExceptionHandler
|
|
|
|
|
public SaResult handlerException(Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
return SaResult.error(e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
注意:在`setDoLoginHandle`函数里如果要获取name, pwd以外的参数,可通过`SaHolder.getRequest().getParam("xxx")`来获取
|
|
|
|
|
|
2024-08-19 17:49:59 +08:00
|
|
|
3、全局异常处理
|
|
|
|
|
``` java
|
|
|
|
|
@RestControllerAdvice
|
|
|
|
|
public class GlobalExceptionHandler {
|
|
|
|
|
@ExceptionHandler
|
|
|
|
|
public SaResult handlerException(Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
return SaResult.error(e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4、创建启动类:
|
2021-07-19 01:12:55 +08:00
|
|
|
``` java
|
|
|
|
|
/**
|
|
|
|
|
* 启动:Sa-OAuth2 Server端
|
|
|
|
|
*/
|
|
|
|
|
@SpringBootApplication
|
|
|
|
|
public class SaOAuth2ServerApplication {
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
SpringApplication.run(SaOAuth2ServerApplication.class, args);
|
2023-06-21 23:10:29 +08:00
|
|
|
System.out.println("\nSa-Token-OAuth Server 端启动成功");
|
2021-07-19 01:12:55 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
启动项目
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 4、访问测试
|
|
|
|
|
|
|
|
|
|
1、由于暂未搭建Client端,我们可以使用Sa-Token官网作为重定向URL进行测试:
|
|
|
|
|
``` url
|
2024-08-19 17:49:59 +08:00
|
|
|
http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=https://sa-token.cc&scope=openid
|
2021-07-19 01:12:55 +08:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2、由于首次访问,我们在OAuth-Server端暂未登录,会被转发到登录视图
|
|
|
|
|
|
2024-08-19 17:49:59 +08:00
|
|
|

|
2021-07-19 01:12:55 +08:00
|
|
|
|
|
|
|
|
3、点击doLogin进行登录之后刷新页面,会提示我们确认授权
|
2024-08-19 17:49:59 +08:00
|
|
|

|
2021-07-19 01:12:55 +08:00
|
|
|
|
|
|
|
|
4、点击确认授权之后刷新页面,我们会被重定向至 redirect_uri 页面,并携带了code参数
|
|
|
|
|
|
2024-08-19 17:49:59 +08:00
|
|
|

|
2021-07-19 01:12:55 +08:00
|
|
|
|
|
|
|
|
4、我们拿着code参数,访问以下地址:
|
|
|
|
|
``` url
|
2024-08-19 17:49:59 +08:00
|
|
|
http://sa-oauth-server.com:8000/oauth2/token?grant_type=authorization_code&client_id=1001&client_secret=aaaa-bbbb-cccc-dddd-eeee&code={code}
|
2021-07-19 01:12:55 +08:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
将得到 `Access-Token`、`Refresh-Token`、`openid`等授权信息
|
|
|
|
|
|
2024-08-19 17:49:59 +08:00
|
|
|
``` js
|
|
|
|
|
{
|
|
|
|
|
"code": 200,
|
|
|
|
|
"msg": "ok",
|
|
|
|
|
"data": null,
|
|
|
|
|
"token_type": "bearer",
|
|
|
|
|
"access_token": "cAls8jnBLmeo5yuCUMwb8zxaSsQPPzGINXF3NOCjCqFHplr6hagdT6A5HeR2",
|
|
|
|
|
"refresh_token": "L2rPbJ3aaOXwaB4Zu0EGWNz5EjVNpw5u2oMP9CS2IEap7rR3Hb76ZqqHS07J",
|
|
|
|
|
"expires_in": 7199,
|
|
|
|
|
"refresh_expires_in": 2591999,
|
|
|
|
|
"client_id": "1001",
|
|
|
|
|
"scope": "openid",
|
|
|
|
|
"openid": "ded91dc189a437dd1bac2274be167d50"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!--  -->
|
2021-07-19 01:12:55 +08:00
|
|
|
|
|
|
|
|
测试完毕
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 5、运行官方示例
|
|
|
|
|
以上代码只是简单模拟了一下OAuth2.0的授权流程,现在,我们运行一下官方示例,里面有制作好的UI界面
|
|
|
|
|
|
2023-05-15 10:25:03 +08:00
|
|
|
- OAuth2-Server端: `/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/` [源码链接](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server) <br/>
|
|
|
|
|
- OAuth2-Client端: `/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-client/` [源码链接](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-client) <br/>
|
2021-07-19 01:12:55 +08:00
|
|
|
|
|
|
|
|
依次启动`OAuth2-Server` 与 `OAuth2-Client`,然后从浏览器访问:[http://sa-oauth-client.com:8002](http://sa-oauth-client.com:8002)
|
|
|
|
|
|
2024-08-19 17:49:59 +08:00
|
|
|

|
2021-07-19 01:12:55 +08:00
|
|
|
|
|
|
|
|
如图,可以针对OAuth2.0四种模式进行详细测试
|
|
|
|
|
|
|
|
|
|
|