华为账号一键登录
服务端实现华为账号一键登录,需通过前端上传的授权码,在服务器获取华为用户信息实现登录业务逻辑。
一、获取用户凭证access\_token
使用POST方式对api <https://oauth-login.cloud.huawei.com/oauth2/v3/token>
发起请求
参数为华为后台提供的应用idclient_id
与密钥client_secret
客户端上传的授权码code
,grant_type
参数固定为authorization_code
注意请求头信息Content-Type为application/x-www-form-urlencoded
php请求示例
引用guzzlehttp包
// 使用guzzlehttp
composer require guzzlehttp/guzzle
发起POST请求,成功获取access_token后应该在过期时间内缓存起来,避免重复请求消耗接口请求次数,增加失败情况后的重试机制。
use GuzzleHttp\Client;
$code = '客户端上传的授权码';
$clientId = '应用id';
$secret = '应用密钥';
$options = [
'http_errors' => false,
'timeout' => 5,
'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
'form_params' => [
'client_id' => $clientId,
'client_secret' => $secret,
'code' => $code,
'grant_type' => 'authorization_code'
]
];
try {
$guzzle = new Client();
$response = $guzzle->post('https://oauth-login.cloud.huawei.com/oauth2/v3/token', $options);
$result = json_decode($response->getBody()->getContents(), true);
} catch (Exception $e) {
// 异常处理
}
// access_toke进行缓存,有效期为1小时,提供失败刷新机制
成功响应结果
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"access_token": "<Access Token>",
"refresh_token": "<Refresh Token>",
"expires_in": 3600,
"id_token": "<ID Token>",
"scope": "openid profile email",
"token_type": "Bearer"
}
失败响应结果
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8
{
"sub_error": 12304,
"error_description": "invalid client_secret",
"error": 1101
}
二、获取用户信息
使用POST方式对api <https://account.cloud.huawei.com/rest.php?nsp_svc=GOpen.User.getInfo>
发起请求,参数为上一步获取的access_token
,成功获取到用户信息后,使用授权用户的手机号或unionid进行应用登录。
注意请求头信息Content-Type为application/x-www-form-urlencoded
请求示例
$options = [
'http_errors' => false,
'timeout' => 5,
'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
'form_params' => [
'access_token' => $token,
]
];
try {
$guzzle = new Client();
$response = $guzzle->post('https://account.cloud.huawei.com/rest.php?nsp_svc=GOpen.User.getInfo', $options);
$result = json_decode($response->getBody()->getContents(), true);
} catch (Exception $e) {
// 异常处理
}
// 使用手机号进行注册或登录逻辑
$mobile = $result['mobileNumber']
成功响应结果
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"displayName": "182******74",
"displayNameFlag": 1,
"mobileNumber": "18211111174",
"openID": "MDFAMTAxMDA1MTg1QGFlMzM0OWIyOGY0*****MDRiaNTI5ODAxYTA3MDh*****A4ZTZmNTA2ZTE4ZT*****lmNGVmN2E1ZjY1OTg4NWRiaN2QxMzQy*****TU0YWQ3",
"unionID": "MDF9pBd6xxxxA8iaG4ZNPTw*****3fyXzG9WgUcmY8XibBvQ",
"headPictureURL": "https://upfile-*****.jpg"
}
失败响应结果
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"error": "session timeout"
}
鸿蒙推送
客户端上报token, 使用token进行业务消息推送到客户端。
一、生成服务账号的鉴权令牌
令牌为JWT格式,包含Header(头部)
、Payload(负载)
、Signature(签名)
三部分组成。
1.创建服务密钥文件(需要在华为开发者联盟上创建并下载推送服务API的服务账号密钥文件)
{
"project_id": "*****",
"key_id": "*****",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCKw6kJKtCh7qmMvp1u1dI27z2TKZrPOzHbQaXO/Eez0AWZ2EN+ouF496R3pfo7fQXC1XOT/YTbVC4DNZwWSMA54fu3/AOCY9Zzyi46OK*****==\n-----END PRIVATE KEY-----\n",
"sub_account": "*****",
"auth_uri": "https://oauth-login.cloud.huawei.com/oauth2/v3/authorize",
"token_uri": "https://oauth-login.cloud.huawei.com/oauth2/v3/token",
"auth_provider_cert_uri": "https://oauth-login.cloud.huawei.com/oauth2/v3/certs",
"client_cert_uri": "https://oauth-login.cloud.huawei.com/oauth2/v3/x509?client_id=*****"
}
2.生成JWT Header信息,kid为账号密钥文件中的key_id
{
"kid": "*****",
"typ": "JWT",
"alg": "PS256"
}
3.生成JWT Payload数据,iss为服务账号密钥文件中sub_account
字段,iat
为当前时间戳 exp
比iat
晚3600秒
{
"aud": "https://oauth-login.cloud.huawei.com/oauth2/v3/token",
"iss": "*****",
"exp": 1581410664,
"iat": 1581407064
}
4.生成JWT Signature签名
将完成BASE64编码后的Header字符串与Payload字符串,通过“.”进行连接,通过服务密钥文件中的private_key
使用SHA256withRSA/PSS算法对拼接的字符串签名。
php代码示例
$header = base64UrlEncode(json_encode([
'kid' => '<key_id>',
'typ' => 'JWT',
'alg' => 'PS256'
]));
$payload = base64UrlEncode(json_encode([
'aud' => 'https://oauth-login.cloud.huawei.com/oauth2/v3/token',
'iss' => '<sub_account>',
'exp' => time() + 3600,
'iat' => time()
]));
// Load the RSA private key
$privateKeyResource = openssl_pkey_get_private($privateKey);
if (!$privateKeyResource) {
die("Failed to load private key.");
}
$unsignedToken = $header . '.' . $payload;
// 签名
openssl_sign($unsignedToken, $signature, $privateKeyResource, 'sha256WithRSAEncryption');
// 拼接jwt
$token = $unsignedToken . '.' . $signature;
// base64编码
function base64UrlEncode($data)
{
return \str_replace('=', '', \strtr(\base64_encode($data), '+/', '-_'));
}
二、消息推送请求
使用POST方式对api https://push-api.cloud.huawei.com/v3/[projectId]/messages:send
发起请求,[projectId]
在请求中替换实际项目id,增加头信息使用上一步获取的jwt鉴权令牌
,并进行拼接,格式为:Authorization:Bearer <token>
注意请求头信息Content-Type为application/json
推送消息内容格式具体参与官方文档与示例:[官方文档] [示例]
php代码示例
$jwt = '<jwt令牌>';
$pushType = 0 //消息类型 0:Alert消息(通知消息、授权订阅消息)1:卡片刷新消息 2:通知扩展消息 6:后台消息 7:实况窗消息 10:应用内通话消息
$projectId = "<项目ID>"
$token = "<用户token>";
// 推送内容
$payload = [
'notification' => [
'category' => 'MARKETING',
'title' => '消息标题',
'body' => '消息描述',
'clickAction' => ['actionType' => $actType]
]
];
// target最大支持10000个token
$body = [
'payload' => $payload,
'target' => [
'token' => [$token]
]
];
$options = [
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $jwt,
'push-type' => $type
],
'http_errors' => false,
'timeout' => 5.0,
'json' => $body,
];
try {
$client = new Client();
$resp = $client->post(sprintf('https://push-api.cloud.huawei.com/v3/%s/messages:send', $projectId), $options);
if ($resp->getStatusCode() != 200) {
return;
}
// 响应结果
$content = json_decode($resp->getBody()->getContents(), true);
if ($content['code'] != '80000000') {
//失败情况处理
}
catch (Exception $e) {
// 异常处理
}