1
0
mirror of synced 2026-05-22 14:43:15 +00:00
Files
Sa-Token/sa-token-doc/oauth2/oauth2-server.md
T
2024-08-19 17:49:59 +08:00

7.3 KiB

搭建OAuth2-Server


1、准备工作

首先修改hosts文件(C:\windows\system32\drivers\etc\hosts),添加以下IP映射,方便我们进行测试:

127.0.0.1 sa-oauth-server.com
127.0.0.1 sa-oauth-client.com

2、引入依赖

创建SpringBoot项目 sa-token-demo-oauth2-server(不会的同学自行百度或参考仓库示例),引入 pom.xml 依赖:

<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc -->
<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>
// Sa-Token 权限认证,在线文档:https://sa-token.cc
implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'

// Sa-Token-OAuth2.0 模块
implementation 'cn.dev33:sa-token-oauth2:${sa.top.version}'

3、开放服务

1、自定义数据加载器:新建 SaOAuth2DataLoaderImpl 实现 SaOAuth2DataLoader 接口。

/**
 * Sa-Token OAuth2:自定义数据加载器
 */
@Component
public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
	
	// 根据 clientId 获取 Client 信息
	@Override
	public SaClientModel getClientModel(String clientId) {
		// 此为模拟数据,真实环境需要从数据库查询 
		if("1001".equals(clientId)) {
			return new SaClientModel()
					.setClientId("1001")    // client id
					.setClientSecret("aaaa-bbbb-cccc-dddd-eeee")    // client 秘钥
					.addAllowUrls("*")    // 所有允许授权的 url
					.addContractScopes("openid", "userid", "userinfo")    // 所有签约的权限
					.setIsAutoMode(true);    // 是否自动判断开放的授权模式 
		}
		return null;
	}
	
	// 根据 clientId 和 loginId 获取 openid
	@Override
	public String getOpenid(String clientId, Object loginId) {
		// 此处使用框架默认算法生成 openid,真实环境建议改为从数据库查询
		return SaOAuth2DataLoader.super.getOpenid(clientId, loginId);
	}

}

你可以在 框架配置 了解有关 SaClientModel 对象所有属性的详细定义

2、新建SaOAuth2ServerController

/**
 * 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) {
		
		// 配置:未登录时返回的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;
		};
	}

	// 全局异常拦截  
	@ExceptionHandler
	public SaResult handlerException(Exception e) {
		e.printStackTrace(); 
		return SaResult.error(e.getMessage());
	}
	
}

注意:在setDoLoginHandle函数里如果要获取name, pwd以外的参数,可通过SaHolder.getRequest().getParam("xxx")来获取

3、全局异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {
	@ExceptionHandler
	public SaResult handlerException(Exception e) {
		e.printStackTrace(); 
		return SaResult.error(e.getMessage());
	}
}

4、创建启动类:

/**
 * 启动:Sa-OAuth2 Server端 
 */
@SpringBootApplication 
public class SaOAuth2ServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(SaOAuth2ServerApplication.class, args);
		System.out.println("\nSa-Token-OAuth Server 端启动成功");
	}
}

启动项目

4、访问测试

1、由于暂未搭建Client端,我们可以使用Sa-Token官网作为重定向URL进行测试:

http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=https://sa-token.cc&scope=openid

2、由于首次访问,我们在OAuth-Server端暂未登录,会被转发到登录视图

sa-oauth2-server-login-view

3、点击doLogin进行登录之后刷新页面,会提示我们确认授权 sa-oauth2-server-scope

4、点击确认授权之后刷新页面,我们会被重定向至 redirect_uri 页面,并携带了code参数

sa-oauth2-server-code

4、我们拿着code参数,访问以下地址:

http://sa-oauth-server.com:8000/oauth2/token?grant_type=authorization_code&client_id=1001&client_secret=aaaa-bbbb-cccc-dddd-eeee&code={code}

将得到 Access-TokenRefresh-Tokenopenid等授权信息

{
  "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"
}

测试完毕

5、运行官方示例

以上代码只是简单模拟了一下OAuth2.0的授权流程,现在,我们运行一下官方示例,里面有制作好的UI界面

  • OAuth2-Server端: /sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/ 源码链接
  • OAuth2-Client端: /sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-client/ 源码链接

依次启动OAuth2-ServerOAuth2-Client,然后从浏览器访问:http://sa-oauth-client.com:8002

sa-oauth2-client-index

如图,可以针对OAuth2.0四种模式进行详细测试