提交 665daa37 编写于 作者: 智布道's avatar 智布道 👁

📝 集成华为

上级 576402ee
## v1.9.6
### 2019/08/05
- 集成华为登录
- 修改`AuthChecker#checkCode`方法,对于不同平台使用不同参数接受code的情况统一做处理
### 2019/08/03
合并github上[xkcoding](https://github.com/xkcoding)[pr#32](https://github.com/zhangyd-c/JustAuth/pull/32),抽取 cache 接口,方便用户自行集成 cache
......
......@@ -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);
......
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());
}
}
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}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册