Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ build/

### VS Code ###
.vscode/

### TEST ###
data.db
logs
keys
142 changes: 142 additions & 0 deletions OAuthAPI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# MioVerify API 接口文档

**Yggdrasil-服务端技术规范** 未规定,但在本项目使用的 API 的文档。

## 基本约定

基本上与 **Yggdrasil-服务端技术规范** 保持一致。

## OAuth 第三方登录/注册

### OAuth 状态查询

`POST /oauth/status`

用于检查 OAuth 是否启用及可用的提供商列表。

响应格式:

```json5
{
"enabled": true,
//ture/false
"providers": [
"microsoft",
"github",
"mcjpg",
"custom"
]
// 已启用的服务商列表
}
```

### 授权端点

`GET /oauth/authorize/{provider}`

将被 `302` 重定向至指定的 Provider ( Authorization Server )的授权页。前端应通过新窗口或直接跳转的方式访问此端点。

### 回调与重定向端点

`GET /oauth/callback/{provider}`

此端点由 Provider 在用户授权后自动调用,**无需前端直接访问**。

后端处理完毕后会将浏览器重定向至配置的 `OAuth 前端回调地址`,并在 URL **查询** 参数中附加以下信息:

| 参数名 | 类型 | 描述 |
|:-------------:|:-------:|:------------------------------------------------------|
| `tempToken` | string | 临时令牌,用于调用 `POST /oauth/authenticate` 换取 `accessToken` |
| `provider` | string | 使用的 OAuth 提供商名称(如 `github`、`microsoft`) |
| `needProfile` | boolean | 是否需要用户创建角色 |
| `userId` | string | 当 `needProfile=true` 时返回用户 ID,便于前端引导创建角色 |

### 登录 Yggdrasil

`POST /oauth/authenticate`

请求格式:

```json5
{
"tempToken": "OAuth 回调端点后返回的临时 Token",
"clientToken": "由客户端指定的令牌的 clientToken(可选)",
"requestUser": false,
// 是否在响应中包含用户信息,默认 false
}
```

若请求中未包含 `clientToken`,服务端应该随机生成一个无符号 UUID 作为 `clientToken`。但需要注意 `clientToken`
可以为任何字符串,即请求中提供任何 `clientToken` 都是可以接受的,不一定要为无符号 UUID。

响应格式:

```json5
{
"accessToken": "令牌的 accessToken",
"clientToken": "令牌的 clientToken",
"availableProfiles": [
// 用户可用角色列表
// ,... 每一项为一个角色(格式见 §角色信息的序列化)
],
"selectedProfile": {
// ... 绑定的角色,若为空,则不需要包含(格式见 §角色信息的序列化)
},
"user": {
// ... 用户信息(仅当请求中 requestUser 为 true 时包含,格式见 §用户信息的序列化)
}
}
```

### 绑定第三方账号到当前用户

`POST /oauth/bind/{provider}`

TODO

将被 `302` 重定向至指定的 Provider ( Authorization Server )的授权页

### 解绑第三方账号

`DELETE /oauth/bind/{provider}`

请求需要带上 HTTP 头部 `Authorization: Bearer {accessToken}` 进行认证。若未包含 Authorization 头或 accessToken 无效,则返回
`401 Unauthorized`。

若用户仅剩一个第三方认证,则解绑失败,返回 `403 Forbidden`

若操作成功或从未绑定这个服务商,服务端应返回 HTTP 状态 `204 No Content`

### 获取所有支持的 OAuth 提供商及当前用户的绑定状态

`GET /oauth/providers`

请求需要带上 HTTP 头部 `Authorization: Bearer {accessToken}` 进行认证。若未包含 Authorization 头或 accessToken 无效,则返回
`401 Unauthorized`。

响应格式:

```json5
{
"providers": [
{
"provider": "唯一标识符", // 例如 github
"bond": true // true or false 表示是否绑定
},
// 可以包含更多
]
}
```

### 登出

`POST /oauth/signout`

请求需要带上 HTTP 头部 `Authorization: Bearer {accessToken}` 进行认证。若未包含 Authorization 头或 accessToken 无效,则返回
`401 Unauthorized`。

若操作成功,服务端应返回 HTTP 状态 `204 No Content`。

## 密码管理

## 其他(待定)
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,27 @@ Yggdrasil API是一套规范,定义了如何实现身份验证。而MioVerify

在项目目录下输入命令行启动对应jar即可。

### 注册 Github Oauth 应用

> [!important]
> 你必须预先注册,否则无法使用 Github Oauth

登录 GitHub → 右上角头像 → Settings → Developer settings → OAuth Apps → New OAuth App。

填写应用信息:

Application name: 你的应用名称(例如 "MyBlog")

Homepage URL: 你的应用首页地址(如 https://yourdomain.com)

Authorization callback URL: 必须填写你部署实例的回调地址,格式如 https://yourdomain.com/oauth/github/callback(注意与 redirect-uri 一致)。

注册成功后,复制 Client ID。

点击 Generate a new client secret,生成并复制 Client Secret(页面关闭后不再显示)。

将这两个值填入部署环境的环境变量中。

## 扩展API

不同于 Yggdrasil API,MioVerify 提供了一套扩展的API,方便调用实现注册等功能,但还需要前端或者客户端继续实现可视化操作。
Expand Down
17 changes: 17 additions & 0 deletions overview.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>MioVerify 项目概述</title>
<meta charset="UTF-8">
</head>
<body>
<h1>MioVerify</h1>
<p><strong>版本:</strong> v1.2.0-BETA (Java 17) <br>
<strong>维护者:</strong> pingguomc (基于 FuziharaYukina 的开发)<br>
<strong>Github:</strong> <a href="https://github.com/pingguomc/MioVerify/" >仓库地址</a> </p>

<p>MioVerify 是一个依据 <a href="https://github.com/yushijinhun/authlib-injector/wiki/Yggdrasil-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83">Yggdrasil 服务端技术规范</a> 实现的 Minecraft 身份验证服务器。本分支专注于支持 OAuth 2 登录系统、修复安全漏洞及性能优化。</p>

@author Fuzihara Yukina (原仓库), pingguomc (当前维护者)
</body>
</html>
6 changes: 5 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</parent>
<groupId>org.miowing</groupId>
<artifactId>MioVerify</artifactId>
<version>1.3.0-alpha</version>
<version>1.4.0</version>
<name>MioVerify</name>
<description>A Minecraft verification server implementing Yggdrasil API</description>
<properties>
Expand Down Expand Up @@ -73,6 +73,10 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
public class MioVerifyApplication {
public static void main(String[] args) {
SpringApplication.run(MioVerifyApplication.class, args);
//
}
}
49 changes: 49 additions & 0 deletions src/main/java/org/miowing/mioverify/config/CorsConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.miowing.mioverify.config;

import lombok.extern.slf4j.Slf4j;
import org.miowing.mioverify.util.DataUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Collections;

/**
* 跨域配置,通常在生产环境中启用
*/
@Slf4j
@Configuration
public class CorsConfig {

@Bean
public CorsFilter corsFilter(DataUtil dataUtil) {
// 未启用跨域,返回空过滤器
if (!dataUtil.isCorsEnabled()) {
return new CorsFilter(new UrlBasedCorsConfigurationSource());
}

CorsConfiguration config = new CorsConfiguration();

String allowedOrigin = dataUtil.getCorsAllowedOrigin();

// 检查配置是否为空
if (allowedOrigin == null || allowedOrigin.trim().isEmpty()) {
log.warn("CORS is enabled, but allowed origin is null or empty");
return new CorsFilter(new UrlBasedCorsConfigurationSource());
}

// 设置允许域
config.setAllowedOriginPatterns(Collections.singletonList(allowedOrigin.trim()));

config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);

return new CorsFilter(source);
}
}
10 changes: 10 additions & 0 deletions src/main/java/org/miowing/mioverify/config/HttpConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class HttpConfig {
@Autowired
private DataUtil dataUtil;

@Bean
public TomcatServletWebServerFactory servletWebServerFactory(Connector connector) {
if (!dataUtil.isSslEnabled()) {
Expand All @@ -33,6 +35,7 @@ protected void postProcessContext(Context context) {
serverFactory.addAdditionalTomcatConnectors(connector);
return serverFactory;
}

@Bean
public Connector createHttpConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Expand All @@ -42,4 +45,11 @@ public Connector createHttpConnector() {
connector.setRedirectPort(dataUtil.getPort());
return connector;
}

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
//
}

}
Loading
Loading