📝 集成华为
This commit is contained in:
@@ -518,6 +518,32 @@ public enum AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://api.stackexchange.com/2.2/me";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 华为
|
||||
* @since 1.9.6
|
||||
*/
|
||||
HUAWEI {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://oauth-login.cloud.huawei.com/oauth2/v2/authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://oauth-login.cloud.huawei.com/oauth2/v2/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://api.vmall.com/rest.php";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refresh() {
|
||||
return "https://oauth-login.cloud.huawei.com/oauth2/v2/token";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,4 +27,11 @@ public class AuthCallback {
|
||||
* 访问AuthorizeUrl后回调时带的参数state,用于和请求AuthorizeUrl前的state比较,防止CSRF攻击
|
||||
*/
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* 华为授权登录接受code的参数名
|
||||
*
|
||||
* @since 1.9.6
|
||||
*/
|
||||
private String authorization_code;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
@Override
|
||||
public AuthResponse login(AuthCallback authCallback) {
|
||||
try {
|
||||
AuthChecker.checkCode(source == AuthSource.ALIPAY ? authCallback.getAuth_code() : authCallback.getCode());
|
||||
AuthChecker.checkCode(source, authCallback);
|
||||
this.checkState(authCallback.getState());
|
||||
|
||||
AuthToken authToken = this.getAccessToken(authCallback);
|
||||
|
||||
194
src/main/java/me/zhyd/oauth/request/AuthHuaweiRequest.java
Normal file
194
src/main/java/me/zhyd/oauth/request/AuthHuaweiRequest.java
Normal file
@@ -0,0 +1,194 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import static me.zhyd.oauth.enums.AuthResponseStatus.SUCCESS;
|
||||
|
||||
/**
|
||||
* 华为授权登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.9.6
|
||||
*/
|
||||
public class AuthHuaweiRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthHuaweiRequest(AuthConfig config) {
|
||||
super(config, AuthSource.HUAWEI);
|
||||
}
|
||||
|
||||
public AuthHuaweiRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.HUAWEI, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access token
|
||||
*
|
||||
* @param authCallback 授权成功后的回调参数
|
||||
* @return token
|
||||
* @see AuthDefaultRequest#authorize()
|
||||
* @see AuthDefaultRequest#authorize(String)
|
||||
*/
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpRequest request = HttpRequest.post(source.accessToken())
|
||||
.form("grant_type", "authorization_code")
|
||||
.form("code", authCallback.getAuthorization_code())
|
||||
.form("client_id", config.getClientId())
|
||||
.form("client_secret", config.getClientSecret())
|
||||
.form("redirect_uri", config.getRedirectUri());
|
||||
return getAuthToken(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用token换取用户信息
|
||||
*
|
||||
* @param authToken token信息
|
||||
* @return 用户信息
|
||||
* @see AuthDefaultRequest#getAccessToken(AuthCallback)
|
||||
*/
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
HttpResponse response = HttpRequest.post(source.userInfo())
|
||||
.form("nsp_ts", System.currentTimeMillis())
|
||||
.form("access_token", authToken.getAccessToken())
|
||||
.form("nsp_fmt", "JS")
|
||||
.form("nsp_svc", "OpenUP.User.getInfo")
|
||||
.execute();
|
||||
JSONObject object = JSONObject.parseObject(response.body());
|
||||
|
||||
this.checkResponse(object);
|
||||
|
||||
AuthUserGender gender = getRealGender(object);
|
||||
|
||||
return AuthUser.builder()
|
||||
.uuid(object.getString("userID"))
|
||||
.username(object.getString("userName"))
|
||||
.nickname(object.getString("userName"))
|
||||
.gender(gender)
|
||||
.avatar(object.getString("headPictureURL"))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新access token (续期)
|
||||
*
|
||||
* @param authToken 登录成功后返回的Token信息
|
||||
* @return AuthResponse
|
||||
*/
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken authToken) {
|
||||
HttpRequest request = HttpRequest.post(source.refresh())
|
||||
.form("client_id", config.getClientId())
|
||||
.form("client_secret", config.getClientSecret())
|
||||
.form("refresh_token", authToken.getRefreshToken())
|
||||
.form("grant_type", "refresh_token");
|
||||
return AuthResponse.builder()
|
||||
.code(SUCCESS.getCode())
|
||||
.data(getAuthToken(request))
|
||||
.build();
|
||||
}
|
||||
|
||||
private AuthToken getAuthToken(HttpRequest request) {
|
||||
HttpResponse response = request.execute();
|
||||
JSONObject object = JSONObject.parseObject(response.body());
|
||||
|
||||
this.checkResponse(object);
|
||||
|
||||
return AuthToken.builder()
|
||||
.accessToken(object.getString("access_token"))
|
||||
.expireIn(object.getIntValue("expires_in"))
|
||||
.refreshToken(object.getString("refresh_token"))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("access_type", "offline")
|
||||
.queryParam("scope", "https%3A%2F%2Fwww.huawei.com%2Fauth%2Faccount%2Fbase.profile")
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取accessToken的url
|
||||
*
|
||||
* @param code 授权码
|
||||
* @return 返回获取accessToken的url
|
||||
*/
|
||||
@Override
|
||||
protected String accessTokenUrl(String code) {
|
||||
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||
.queryParam("grant_type", "authorization_code")
|
||||
.queryParam("code", code)
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("client_secret", config.getClientSecret())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取userInfo的url
|
||||
*
|
||||
* @param authToken token
|
||||
* @return 返回获取userInfo的url
|
||||
*/
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("nsp_ts", System.currentTimeMillis())
|
||||
.queryParam("access_token", authToken.getAccessToken())
|
||||
.queryParam("nsp_fmt", "JS")
|
||||
.queryParam("nsp_svc", "OpenUP.User.getInfo")
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的实际性别。华为系统中,用户的性别:1表示女,0表示男
|
||||
*
|
||||
* @param object obj
|
||||
* @return AuthUserGender
|
||||
*/
|
||||
private AuthUserGender getRealGender(JSONObject object) {
|
||||
int genderCodeInt = object.getIntValue("gender");
|
||||
String genderCode = genderCodeInt == 1 ? "0" : (genderCodeInt == 0) ? "1" : genderCodeInt + "";
|
||||
return AuthUserGender.getRealGender(genderCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验响应结果
|
||||
*
|
||||
* @param object 接口返回的结果
|
||||
*/
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (object.containsKey("error")) {
|
||||
if (!object.containsKey("sub_error") && !object.containsKey("error_description")) {
|
||||
throw new AuthException(object.getString("error"));
|
||||
}
|
||||
throw new AuthException(object.getString("sub_error") + ":" + object.getString("error_description"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
|
||||
/**
|
||||
* 授权配置类的校验器
|
||||
@@ -56,11 +57,20 @@ public class AuthChecker {
|
||||
|
||||
/**
|
||||
* 校验回调传回的code
|
||||
* <p>
|
||||
* {@code v1.9.6}版本中改为传入{@code source}和{@code callback},对于不同平台使用不同参数接受code的情况统一做处理
|
||||
*
|
||||
* @param code 回调时传回的code
|
||||
* @param source 当前授权平台
|
||||
* @param callback 从第三方授权回调回来时传入的参数集合
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public static void checkCode(String code) {
|
||||
public static void checkCode(AuthSource source, AuthCallback callback) {
|
||||
String code = callback.getCode();
|
||||
if (source == AuthSource.ALIPAY) {
|
||||
code = callback.getAuth_code();
|
||||
} else if (source == AuthSource.HUAWEI) {
|
||||
code = callback.getAuthorization_code();
|
||||
}
|
||||
if (StringUtils.isEmpty(code)) {
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_CODE);
|
||||
}
|
||||
|
||||
@@ -277,4 +277,18 @@ public class AuthRequestTest {
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void huaweiTest() {
|
||||
AuthRequest authRequest = new AuthHuaweiRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
}
|
||||
|
||||
41
src/test/java/me/zhyd/oauth/sdk/ThirdPartSdkTest.java
Normal file
41
src/test/java/me/zhyd/oauth/sdk/ThirdPartSdkTest.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package me.zhyd.oauth.sdk;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.9.6
|
||||
*/
|
||||
public class ThirdPartSdkTest {
|
||||
|
||||
@Test
|
||||
public void huawei() {
|
||||
String code = "CF1IE8WDUI7HR0cTOcl59SHBmIo0EGugnY99HTnLjH0BiCu5+maSDDejA7V2FJntFGfdTXY/jD68WZAVW2cMZoXrHW0LHVQ+uYqb498PkdI453sejJcaSIS6bBCZJBNzrYKGk4PYWc5OS/yuPorSSNRlXXhjN9selraIOF+TBMb7wzXDho7FVz/Es2rInRfttnr3AEaIvkg=";
|
||||
HttpResponse response = HttpRequest.post("https://oauth-login.cloud.huawei.com/oauth2/v2/token")
|
||||
.form("grant_type", "authorization_code")
|
||||
.form("code", code)
|
||||
.form("client_id", "100994535")
|
||||
.form("client_secret", "22aea400bef603fef26d15a79c806eb477b35de0a529758f2a3b1bda32bfb80d")
|
||||
.form("redirect_uri", "http://localhost:8443/huawei/login")
|
||||
.execute();
|
||||
System.out.println(response.body());
|
||||
|
||||
// {"access_token":"CF1IGrYGi\/s0JddMwEQ1i0xBwWI7CepxuAm9HP9wvjuPOYyXItkSh6PVLfeD7AcDD3BS0APzgyyrS\/GK9FF9Hk91WrAROGfTfTVlh0DdEw9k4NW77EjQmA==","expires_in":3600,"refresh_token":"CF41WqZNkgaJhDtW1Kv5rypr8PklmwVsKlAbFLXmxte0mrTdvJd9k8vTrIlw5NoMnNn7nZ2b3fpgsl4zabm10QQEHY2H+s5qwx1dxXR\/arV6JQ9OYMDk+A==","scope":"https:\/\/www.huawei.com\/auth\/account\/mobile.number https:\/\/www.huawei.com\/auth\/account\/base.profile","token_type":"Bearer"}
|
||||
|
||||
//
|
||||
HttpResponse response2 = HttpRequest.post("https://api.vmall.com/rest.php")
|
||||
.form("nsp_ts", System.currentTimeMillis())
|
||||
.form("access_token", JSONObject.parseObject(response.body()).getString("access_token"))
|
||||
.form("nsp_fmt", "JS")
|
||||
// .form("nsp_cb", "")
|
||||
.form("nsp_svc", "OpenUP.User.getInfo")
|
||||
.execute();
|
||||
System.out.println(response2.body());
|
||||
// 华为性别 0是男,女是1
|
||||
// {"gender":1,"headPictureURL":"https://upfile-drcn.platform.hicloud.com/FileServer/image/b.0260086000226601572.20190415065228.iBKdTsqaNkdPXSz4N7pIRWAgeu45ec3k.1000.9A5467309F9284B267ECA33B59D3D7DA4A71BC732D3BB24EC6B880A73DEE9BAB.jpg","languageCode":"zh-CN","userID":"260086000226601572","userName":"151****2326","userState":1,"userValidStatus":1}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user