Difference between revisions of "Zh:Authentication"
Hempflower (talk | contribs) (→错误) |
(暴力更新不可取) |
||
Line 1: | Line 1: | ||
− | Minecraft 1. | + | Minecraft 1.6引入了一种全新的叫作'''Yggdrasil'''的认证方案,它彻底地取代了[[ZH:旧版认证|先前的认证系统]]。Mojang的其他游戏,Scrolls,同样也使用了该认证方法。Mojang曾经说过[https://twitter.com/KrisJelbring/status/453573406341206016 每个人都应使用此认证系统来进行自定义登录],但是[https://twitter.com/KrisJelbring/status/461390585086361600 永远不会从用户收集凭据]。 |
== 请求格式 == | == 请求格式 == | ||
− | + | 所有对Yggdrasil的请求都会发送到以下服务器: | |
− | |||
https://authserver.mojang.com | https://authserver.mojang.com | ||
− | + | 此外,它们应满足以下规则: | |
− | * | + | * 为<code>POST</code>请求 |
− | * | + | * <code>Content-Type</code>头设置为<code>application/json</code> |
− | * | + | * 以包含[[wikipedia:zh:JSON|JSON]]编码的字典作为负载 |
+ | 如果请求成功,服务器将响应: | ||
− | + | * 状态码<code>200</code> | |
+ | * 根据以下规范使用[[wikipedia:zh:JSON|JSON]]编码的字典 | ||
− | + | 但如果请求失败,服务器会响应: | |
− | |||
− | |||
− | * | + | * 适当的非200[[wikipedia:zh:HTTP状态码|HTTP状态码]] |
− | * | + | * 拥有以下格式的[[wikipedia:zh:JSON|JSON]]编码的字典: |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
− | "error": " | + | "error": "错误的简短描述", |
− | "errorMessage": " | + | "errorMessage": "用于向用户显示的更长的描述", |
− | "cause": " | + | "cause": "错误原因" // 可选的 |
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 33: | Line 32: | ||
== 错误 == | == 错误 == | ||
− | + | 这些是可能遇到的一些错误: | |
{| class="wikitable" | {| class="wikitable" | ||
Line 39: | Line 38: | ||
! 错误 | ! 错误 | ||
! 原因 | ! 原因 | ||
− | ! | + | ! 错误信息 |
! 注释 | ! 注释 | ||
|- | |- | ||
| <code>Method Not Allowed</code> | | <code>Method Not Allowed</code> | ||
| | | | ||
− | | | + | | The method specified in the request is not allowed for the resource identified by the request URI<br/>请求URI中标识的资源不允许使用请求中指定的方法 |
− | | | + | | 收到了除POST请求以外的信息。 |
|- | |- | ||
| <code>Not Found</code> | | <code>Not Found</code> | ||
| | | | ||
− | | | + | | The server has not found anything matching the request URI<br/>服务器未找到与请求URI匹配的任何内容 |
− | | | + | | 调用了不存在的端点。 |
|- | |- | ||
| <code>ForbiddenOperationException</code> | | <code>ForbiddenOperationException</code> | ||
| <code>UserMigratedException</code> | | <code>UserMigratedException</code> | ||
− | | | + | | Invalid credentials. Account migrated, use e-mail as username.<br/>无效凭据。账号已迁移,使用邮箱作为用户名。 |
| | | | ||
|- | |- | ||
| <code>ForbiddenOperationException</code> | | <code>ForbiddenOperationException</code> | ||
| | | | ||
− | | | + | | Invalid credentials. Invalid username or password.<br/>无效凭据。无效的用户名或密码。 |
| | | | ||
|- | |- | ||
| <code>ForbiddenOperationException</code> | | <code>ForbiddenOperationException</code> | ||
| | | | ||
− | | | + | | Invalid credentials.<br/>无效凭据。 |
− | | | + | | 该用户名最近的尝试登录过多(见<code>/authenticate</code>)。注意用户名和密码可能仍然有效! |
|- | |- | ||
| <code>ForbiddenOperationException</code> | | <code>ForbiddenOperationException</code> | ||
| | | | ||
− | | Invalid token. | + | | Invalid token.<br/>无效凭据。 |
− | | <code>accessToken</code> | + | | <code>accessToken</code>失效了。 |
|- | |- | ||
| <code>IllegalArgumentException</code> | | <code>IllegalArgumentException</code> | ||
| | | | ||
− | | Access token already has a profile assigned. | + | | Access token already has a profile assigned.<br/>访问令牌已经被分配了档案。 |
− | | | + | | 还没有实现选择档案。 |
|- | |- | ||
| <code>IllegalArgumentException</code> | | <code>IllegalArgumentException</code> | ||
| | | | ||
− | | credentials is null | + | | credentials is null<br/>凭据为空 |
− | | | + | | 用户名/密码未提交。 |
|- | |- | ||
| <code>IllegalArgumentException</code> | | <code>IllegalArgumentException</code> | ||
| | | | ||
− | | Invalid salt version | + | | Invalid salt version<br/>无效的盐版本 |
− | | | + | | ??? |
|- | |- | ||
| <code>Unsupported Media Type</code> | | <code>Unsupported Media Type</code> | ||
| | | | ||
− | | The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method | + | | The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method<br/>服务器拒绝为请求提供服务,因为请求实体的格式不受请求方法所请求的资源支持 |
− | | | + | | 数据未提交为application / json |
|} | |} | ||
− | == | + | == 认证 == |
− | + | 使用密码认证用户。 | |
− | === | + | === 端点 === |
/authenticate | /authenticate | ||
− | === | + | === 负载 === |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
− | "agent": { // | + | "agent": { // 默认为Minecraft |
− | "name": "Minecraft", // | + | "name": "Minecraft", // 对于Mojang的其他游戏Scrolls,则应该使用"Scrolls" |
− | "version": 1 // | + | "version": 1 // 以后的原版客户端 |
− | // | + | // 可能会增加该数字 |
}, | }, | ||
− | "username": " | + | "username": "mojang帐号名", // 可以是电子邮箱地址或 |
− | // | + | // 玩家名称(对于为迁移的账号) |
− | "password": " | + | "password": "mojang帐号密码", |
− | "clientToken": " | + | "clientToken": "客户端标识符", // 可选的 |
− | "requestUser": true // | + | "requestUser": true // 可选的,默认为false,若为true则将user对象加入到响应中 |
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | <code>clientToken</code>应该是一个随机生成的标识符而且必须每次请求都是相同的。原版启动器会在第一次运行时生成一个随机的(v4)UUID并保存,在后续每次请求中复用它。如果省略,那么服务器会生成一个基于Java的[http://docs.oracle.com/javase/7/docs/api/java/util/UUID.html#toString() <code>UUID.toString()</code>]的随机令牌,它应该由客户端保存下来。然而这也会使用户之前在所有客户端上获取的<code>accessToken</code>失效。 | |
− | === | + | === 响应 === |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
− | "accessToken": " | + | "accessToken": "随机访问令牌", // 十六进制或JSON-Web-Token(未确认)[普通accessToken可以在JWT的响应中找到(使用‘.’分隔的第二部分,以Base64编码的JSON对象),在“yggt”键中] |
− | "clientToken": " | + | "clientToken": "客户端标识符", // 与接收到的相同 |
− | "availableProfiles": [ // | + | "availableProfiles": [ // 仅在接收到agent字段时出现 |
{ | { | ||
− | "agent": "minecraft", // | + | "agent": "minecraft", // 可能与之前值相同 |
− | "id": " | + | "id": "档案标识符", // 十六进制 |
− | "name": " | + | "name": "玩家名称", |
− | "userId": " | + | "userId": "十六进制字符串", |
− | "createdAt": 1325376000000, // | + | "createdAt": 1325376000000, // 自1970年1月1日起的毫秒数 |
− | "legacyProfile": | + | "legacyProfile": true或false, // 即使为false也出现 |
− | "suspended": | + | "suspended": true或false, // 可能为false |
− | "paid": | + | "paid": true或false, // 可能为true |
− | "migrated": | + | "migrated": true或false, // 似乎即使是已迁移账号也为false…?(https://bugs.mojang.com/browse/WEB-1461) |
− | "legacy": | + | "legacy": true或false // 它仅为true时出现。默认为false。与较新的legacyProfile重复… |
} | } | ||
], | ], | ||
− | "selectedProfile": { // | + | "selectedProfile": { // 仅在接收到agent字段时出现 |
− | "id": " | + | "id": "不含分隔符的uuid", |
− | "name": " | + | "name": "玩家名称", |
− | "userId": " | + | "userId": "十六进制字符串", |
"createdAt": 1325376000000, | "createdAt": 1325376000000, | ||
− | "legacyProfile": | + | "legacyProfile": true或false, |
− | "suspended": | + | "suspended": true或false, |
− | "paid": | + | "paid": true或false, |
− | "migrated": | + | "migrated": true或false, |
− | "legacy": | + | "legacy": true或false |
}, | }, | ||
− | "user": { // | + | "user": { // 仅在请求负载中的requestUser为true出现 |
− | "id": " | + | "id": "用户标识符", // 十六进制 |
− | "email": "user@email.example", // | + | "email": "user@email.example", // 未迁移账号的哈希(?)值 |
− | "username": "user@email.example", // | + | "username": "user@email.example", // 未迁移账号的正常名称或已迁移账号的电子邮箱 |
− | "registerIp": "198.51.100.*", // | + | "registerIp": "198.51.100.*", // 最后一位打码的IP地址 |
"migratedFrom": "minecraft.net", | "migratedFrom": "minecraft.net", | ||
"migratedAt": 1420070400000, | "migratedAt": 1420070400000, | ||
− | "registeredAt": 1325376000000, // | + | "registeredAt": 1325376000000, // 也许比profile的createdAt要早几分钟 |
"passwordChangedAt": 1569888000000, | "passwordChangedAt": 1569888000000, | ||
"dateOfBirth": -2208988800000, | "dateOfBirth": -2208988800000, | ||
Line 164: | Line 163: | ||
"blocked": false, | "blocked": false, | ||
"secured": true, | "secured": true, | ||
− | "migrated": false, // | + | "migrated": false, // 似乎即使migratedAt和migratedFrom出现时也为false… |
"emailVerified": true, | "emailVerified": true, | ||
"legacyUser": false, | "legacyUser": false, | ||
Line 170: | Line 169: | ||
"properties": [ | "properties": [ | ||
{ | { | ||
− | "name": "preferredLanguage", // | + | "name": "preferredLanguage", // 也许不会对所有账号显示 |
− | "value": "en" // Java | + | "value": "en" // Java locale格式 (https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#toString--) |
}, | }, | ||
{ | { | ||
− | "name": "twitch_access_token", // | + | "name": "twitch_access_token", // 仅在关联twitch账号时出现(见https://account.mojang.com/me/settings) |
− | "value": "twitch oauth token" // OAuth 2. | + | "value": "twitch oauth token" // OAuth 2.0令牌,字母+数字,如https://api.twitch.tv/kraken?oauth_token=[...] |
− | // | + | // Twitch API的文档:https://github.com/justintv/Twitch-API |
} | } | ||
] | ] | ||
Line 183: | Line 182: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | ''' | + | '''注意:'''如果用户希望能在他们的电脑上保存登录状态,那么强烈建议应该存储<code>accessToken</code>而不是密码本身。 |
− | + | 当前每个账号只拥有一个档案,一个账号拥有多个档案还在未来计划中。如果用户尝试登入一个没有附加Minecraft许可的Mojang账号,那么认证将会成功,但是响应将不包含<code>selectedProfile</code>字段,而且<code>availableProfiles</code>数组也是空的。 | |
− | + | 有一些实例曾观察到Mojang对于旧版账号失败的刷新请求返回了一个平坦的<code>null</code>。还不清楚什么实际错误绑定了这个空响应,而且它极为罕见,但作为实现应该注意对该响应的空输出。 | |
− | + | 这个端点是严格速率限制的:短时间内同一账号的多次<code>/authenticate</code>请求(例如在几秒内3次请求),即使密码正确也会导致一个<code>Invalid credentials.</code>响应。该错误会在几秒后被清除。 | |
− | == | + | == 刷新 == |
− | + | 刷新一个有效的<code>accessToken</code>。它可以用于在游戏会话间保持登录状态,这优于在文件中保存用户的密码(见[[ZH:lastlogin|lastlogin]])。 | |
− | === | + | === 端点 === |
/refresh | /refresh | ||
− | === | + | === 负载 === |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
− | "accessToken": " | + | "accessToken": "有效的accessToken", |
− | "clientToken": " | + | "clientToken": "客户端标识符", // 这需要与第一处用来获取 |
− | // | + | // accessToken的那个相同 |
− | "selectedProfile": { // | + | "selectedProfile": { // 可选的,发送它将导致错误 |
− | "id": " | + | "id": "档案标识符", // 十六进制 |
− | "name": " | + | "name": "玩家名称" |
}, | }, | ||
− | "requestUser": true // | + | "requestUser": true // 可选的,默认为false,若为true则将user对象加入到响应中 |
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | 注意:提供的<code>accessToken</code>将失效。 | |
− | === | + | === 响应 === |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
− | "accessToken": " | + | "accessToken": "随机访问令牌", // 十六进制 |
− | "clientToken": " | + | "clientToken": "客户端标识符", // 与接收到的相同 |
"selectedProfile": { | "selectedProfile": { | ||
− | "id": " | + | "id": "档案标识符", // 十六进制 |
− | "name": " | + | "name": "玩家名称" |
}, | }, | ||
− | "user": { // | + | "user": { // 仅在请求负载中的requestUser为true出现 |
− | "id": " | + | "id": "用户标识符", // 十六进制 |
"properties": [ | "properties": [ | ||
{ | { | ||
− | "name": "preferredLanguage", // | + | "name": "preferredLanguage", // 也许不会对所有账号显示 |
− | "value": "en" // Java | + | "value": "en" // Java locale格式(https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#toString--) |
}, | }, | ||
{ | { | ||
− | "name": "twitch_access_token", // | + | "name": "twitch_access_token", // 仅在关联twitch账号时出现(见https://account.mojang.com/me/settings) |
− | "value": "twitch oauth token" // OAuth 2. | + | "value": "twitch oauth token" // OAuth 2.0令牌,字母+数字,如https://api.twitch.tv/kraken?oauth_token=[...] |
− | // | + | // Twitch API的文档:https://github.com/justintv/Twitch-API |
} | } | ||
] | ] | ||
Line 242: | Line 241: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | == | + | == 验证 == |
− | + | 检查<code>accessToken</code>是否可用于Minecraft服务器的认证。Minecraft启动器(自1.6.13版本起)会在启动器调用此端点来验证保存的令牌是否仍然可用,并会在返回错误时调用<code>/refresh</code>。 | |
− | + | 请注意<code>accessToken</code>可能会不可用与Minecraft服务器的认证,而对于<code>/refresh</code>来说足够可用。这主要会发生在一个人使用了另一个客户端(如在别的PC上使用相同的帐号游玩了Minecraft)。看起来只有给定帐号最新获得的<code>accessToken</code>才能可靠地用于认证(第二新的令牌看起来也仍然有效,但请不要依赖它)。 | |
− | <code>/validate</code> | + | <code>/validate</code>可以在有或没有<code>clientToken</code>时调用。如果提供了<code>clientToken</code>,它应当与获取<code>accessToken</code>的那个相匹配。Minecraft启动器会向<code>/validate</code>发送<code>clientToken</code>。 |
− | === | + | === 端点 === |
/validate | /validate | ||
− | === | + | === 负载 === |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
− | "accessToken": " | + | "accessToken": "有效的accessToken", |
− | "clientToken": " | + | "clientToken": "关联的clientToken" // 可选的,见上 |
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === | + | === 响应 === |
− | + | 若成功返回空响应(<code>204 No Content</code>),否则返回错误JSON和状态码<code>403 Forbidden</code>。 | |
− | == | + | == 登出 == |
− | + | 使用帐号的用户名和密码使<code>accessToken</code>失效。 | |
− | === | + | === 端点 === |
/signout | /signout | ||
− | === | + | === 负载 === |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
− | "username": " | + | "username": "mojang帐号名称", |
− | "password": " | + | "password": "mojang帐号密码" |
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === | + | === 响应 === |
− | + | 若成功返回一个空负载。 | |
− | == | + | == 使失效 == |
− | + | 使用client/access令牌对使<code>accessToken</code>失效。 | |
− | === | + | === 端点 === |
/invalidate | /invalidate | ||
− | === | + | === 负载 === |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
− | "accessToken": " | + | "accessToken": "有效的accessToken", |
− | "clientToken": " | + | "clientToken": "客户端标识符" // 这需要与第一处用来获取 |
− | // | + | // accessToken的那个相同 |
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === | + | === 响应 === |
− | + | 若成功返回一个空负载。 | |
− | == | + | == 加入服务器 == |
− | + | 见[[ZH:协议加密#认证|协议加密#认证]] | |
− | [[Category:Protocol Details]] | + | [[Category:ZH:Protocol Details]] |
− | [[Category:Minecraft Modern]] | + | [[Category:ZH:Minecraft Modern]] |
Revision as of 09:30, 11 November 2019
Minecraft 1.6引入了一种全新的叫作Yggdrasil的认证方案,它彻底地取代了先前的认证系统。Mojang的其他游戏,Scrolls,同样也使用了该认证方法。Mojang曾经说过每个人都应使用此认证系统来进行自定义登录,但是永远不会从用户收集凭据。
Contents
请求格式
所有对Yggdrasil的请求都会发送到以下服务器:
https://authserver.mojang.com
此外,它们应满足以下规则:
- 为
POST
请求 Content-Type
头设置为application/json
- 以包含JSON编码的字典作为负载
如果请求成功,服务器将响应:
- 状态码
200
- 根据以下规范使用JSON编码的字典
但如果请求失败,服务器会响应:
{
"error": "错误的简短描述",
"errorMessage": "用于向用户显示的更长的描述",
"cause": "错误原因" // 可选的
}
错误
这些是可能遇到的一些错误:
错误 | 原因 | 错误信息 | 注释 |
---|---|---|---|
Method Not Allowed
|
The method specified in the request is not allowed for the resource identified by the request URI 请求URI中标识的资源不允许使用请求中指定的方法 |
收到了除POST请求以外的信息。 | |
Not Found
|
The server has not found anything matching the request URI 服务器未找到与请求URI匹配的任何内容 |
调用了不存在的端点。 | |
ForbiddenOperationException
|
UserMigratedException
|
Invalid credentials. Account migrated, use e-mail as username. 无效凭据。账号已迁移,使用邮箱作为用户名。 |
|
ForbiddenOperationException
|
Invalid credentials. Invalid username or password. 无效凭据。无效的用户名或密码。 |
||
ForbiddenOperationException
|
Invalid credentials. 无效凭据。 |
该用户名最近的尝试登录过多(见/authenticate )。注意用户名和密码可能仍然有效!
| |
ForbiddenOperationException
|
Invalid token. 无效凭据。 |
accessToken 失效了。
| |
IllegalArgumentException
|
Access token already has a profile assigned. 访问令牌已经被分配了档案。 |
还没有实现选择档案。 | |
IllegalArgumentException
|
credentials is null 凭据为空 |
用户名/密码未提交。 | |
IllegalArgumentException
|
Invalid salt version 无效的盐版本 |
??? | |
Unsupported Media Type
|
The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method 服务器拒绝为请求提供服务,因为请求实体的格式不受请求方法所请求的资源支持 |
数据未提交为application / json |
认证
使用密码认证用户。
端点
/authenticate
负载
{
"agent": { // 默认为Minecraft
"name": "Minecraft", // 对于Mojang的其他游戏Scrolls,则应该使用"Scrolls"
"version": 1 // 以后的原版客户端
// 可能会增加该数字
},
"username": "mojang帐号名", // 可以是电子邮箱地址或
// 玩家名称(对于为迁移的账号)
"password": "mojang帐号密码",
"clientToken": "客户端标识符", // 可选的
"requestUser": true // 可选的,默认为false,若为true则将user对象加入到响应中
}
clientToken
应该是一个随机生成的标识符而且必须每次请求都是相同的。原版启动器会在第一次运行时生成一个随机的(v4)UUID并保存,在后续每次请求中复用它。如果省略,那么服务器会生成一个基于Java的UUID.toString()
的随机令牌,它应该由客户端保存下来。然而这也会使用户之前在所有客户端上获取的accessToken
失效。
响应
{
"accessToken": "随机访问令牌", // 十六进制或JSON-Web-Token(未确认)[普通accessToken可以在JWT的响应中找到(使用‘.’分隔的第二部分,以Base64编码的JSON对象),在“yggt”键中]
"clientToken": "客户端标识符", // 与接收到的相同
"availableProfiles": [ // 仅在接收到agent字段时出现
{
"agent": "minecraft", // 可能与之前值相同
"id": "档案标识符", // 十六进制
"name": "玩家名称",
"userId": "十六进制字符串",
"createdAt": 1325376000000, // 自1970年1月1日起的毫秒数
"legacyProfile": true或false, // 即使为false也出现
"suspended": true或false, // 可能为false
"paid": true或false, // 可能为true
"migrated": true或false, // 似乎即使是已迁移账号也为false…?(https://bugs.mojang.com/browse/WEB-1461)
"legacy": true或false // 它仅为true时出现。默认为false。与较新的legacyProfile重复…
}
],
"selectedProfile": { // 仅在接收到agent字段时出现
"id": "不含分隔符的uuid",
"name": "玩家名称",
"userId": "十六进制字符串",
"createdAt": 1325376000000,
"legacyProfile": true或false,
"suspended": true或false,
"paid": true或false,
"migrated": true或false,
"legacy": true或false
},
"user": { // 仅在请求负载中的requestUser为true出现
"id": "用户标识符", // 十六进制
"email": "user@email.example", // 未迁移账号的哈希(?)值
"username": "user@email.example", // 未迁移账号的正常名称或已迁移账号的电子邮箱
"registerIp": "198.51.100.*", // 最后一位打码的IP地址
"migratedFrom": "minecraft.net",
"migratedAt": 1420070400000,
"registeredAt": 1325376000000, // 也许比profile的createdAt要早几分钟
"passwordChangedAt": 1569888000000,
"dateOfBirth": -2208988800000,
"suspended": false,
"blocked": false,
"secured": true,
"migrated": false, // 似乎即使migratedAt和migratedFrom出现时也为false…
"emailVerified": true,
"legacyUser": false,
"verifiedByParent": false,
"properties": [
{
"name": "preferredLanguage", // 也许不会对所有账号显示
"value": "en" // Java locale格式 (https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#toString--)
},
{
"name": "twitch_access_token", // 仅在关联twitch账号时出现(见https://account.mojang.com/me/settings)
"value": "twitch oauth token" // OAuth 2.0令牌,字母+数字,如https://api.twitch.tv/kraken?oauth_token=[...]
// Twitch API的文档:https://github.com/justintv/Twitch-API
}
]
}
}
注意:如果用户希望能在他们的电脑上保存登录状态,那么强烈建议应该存储accessToken
而不是密码本身。
当前每个账号只拥有一个档案,一个账号拥有多个档案还在未来计划中。如果用户尝试登入一个没有附加Minecraft许可的Mojang账号,那么认证将会成功,但是响应将不包含selectedProfile
字段,而且availableProfiles
数组也是空的。
有一些实例曾观察到Mojang对于旧版账号失败的刷新请求返回了一个平坦的null
。还不清楚什么实际错误绑定了这个空响应,而且它极为罕见,但作为实现应该注意对该响应的空输出。
这个端点是严格速率限制的:短时间内同一账号的多次/authenticate
请求(例如在几秒内3次请求),即使密码正确也会导致一个Invalid credentials.
响应。该错误会在几秒后被清除。
刷新
刷新一个有效的accessToken
。它可以用于在游戏会话间保持登录状态,这优于在文件中保存用户的密码(见lastlogin)。
端点
/refresh
负载
{
"accessToken": "有效的accessToken",
"clientToken": "客户端标识符", // 这需要与第一处用来获取
// accessToken的那个相同
"selectedProfile": { // 可选的,发送它将导致错误
"id": "档案标识符", // 十六进制
"name": "玩家名称"
},
"requestUser": true // 可选的,默认为false,若为true则将user对象加入到响应中
}
注意:提供的accessToken
将失效。
响应
{
"accessToken": "随机访问令牌", // 十六进制
"clientToken": "客户端标识符", // 与接收到的相同
"selectedProfile": {
"id": "档案标识符", // 十六进制
"name": "玩家名称"
},
"user": { // 仅在请求负载中的requestUser为true出现
"id": "用户标识符", // 十六进制
"properties": [
{
"name": "preferredLanguage", // 也许不会对所有账号显示
"value": "en" // Java locale格式(https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#toString--)
},
{
"name": "twitch_access_token", // 仅在关联twitch账号时出现(见https://account.mojang.com/me/settings)
"value": "twitch oauth token" // OAuth 2.0令牌,字母+数字,如https://api.twitch.tv/kraken?oauth_token=[...]
// Twitch API的文档:https://github.com/justintv/Twitch-API
}
]
}
}
验证
检查accessToken
是否可用于Minecraft服务器的认证。Minecraft启动器(自1.6.13版本起)会在启动器调用此端点来验证保存的令牌是否仍然可用,并会在返回错误时调用/refresh
。
请注意accessToken
可能会不可用与Minecraft服务器的认证,而对于/refresh
来说足够可用。这主要会发生在一个人使用了另一个客户端(如在别的PC上使用相同的帐号游玩了Minecraft)。看起来只有给定帐号最新获得的accessToken
才能可靠地用于认证(第二新的令牌看起来也仍然有效,但请不要依赖它)。
/validate
可以在有或没有clientToken
时调用。如果提供了clientToken
,它应当与获取accessToken
的那个相匹配。Minecraft启动器会向/validate
发送clientToken
。
端点
/validate
负载
{
"accessToken": "有效的accessToken",
"clientToken": "关联的clientToken" // 可选的,见上
}
响应
若成功返回空响应(204 No Content
),否则返回错误JSON和状态码403 Forbidden
。
登出
使用帐号的用户名和密码使accessToken
失效。
端点
/signout
负载
{
"username": "mojang帐号名称",
"password": "mojang帐号密码"
}
响应
若成功返回一个空负载。
使失效
使用client/access令牌对使accessToken
失效。
端点
/invalidate
负载
{
"accessToken": "有效的accessToken",
"clientToken": "客户端标识符" // 这需要与第一处用来获取
// accessToken的那个相同
}
响应
若成功返回一个空负载。