提交 75a791ff 编写于 作者: 如梦技术's avatar 如梦技术 🐛

添加 mica-social 第三方登录组件.

上级 8e5e6c30
......@@ -63,6 +63,9 @@
### mica-captcha
- 验证码,支持 `webflux``serlvet`
### mica-social
- 第三方登录组件
### mica-cloud
- Feign 自动降级、header 透传、版本处理,结合 `mica-auto` 自动化配置。
- RestTemplate自动配置,基于okhttp增强,添加请求日志和Header传递。
......
ext {
javaVersion = JavaVersion.VERSION_1_8
springBootVersion = "2.1.5.RELEASE"
springBootVersion = "2.1.6.RELEASE"
springCloudVersion = "Greenwich.SR1"
springCloudAlibabaVersion = "0.9.0.RELEASE"
micaAutoVersion = "1.1.0"
apolloVersion = "1.3.0"
apolloVersion = "1.4.0"
protostuffVersion = "1.6.0"
disruptorVersion = "3.4.2"
swaggerVersion = "2.9.2"
swaggerBootstrapUiVersion = "1.9.4"
alipaySdkVersion = "3.7.4.ALL"
lombokVersion = "1.18.8"
findbugsVersion = "3.0.2"
}
......
# 第三方登录组件
`mica-social`,如你所见,它仅仅是一个**第三方授权登录****工具类库**,它可以让我们脱离繁琐的第三方登录SDK,让登录变得**So easy!**
## API列表
| :computer: 平台 |
|:------:|
| gitee |
| github |
| weibo |
| dingtalk |
| baidu |
| coding |
| tencentCloud |
| oschina |
| alipay |
| qq |
| wechat |
| taobao |
| google |
| facebook |
| douyin |
| linkedin |
| microsoft |
| mi |
| toutiao |
| csdn |
_请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经下线。如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了_
## 添加依赖
### maven
```xml
<dependency>
<groupId>net.dreamlu</groupId>
<artifactId>mica-social</artifactId>
<version>${version}</version>
</dependency>
```
### gradle
```groovy
compile("net.dreamlu:mica-social:${version}")
```
## 鸣谢
`mica-social` 修改与 [`JustAuth`](https://github.com/zhangyd-c/JustAuth),感谢 `JustAuth` 所有开发者的奉献。
\ No newline at end of file
dependencies {
api project(":mica-http")
implementation "com.alipay.sdk:alipay-sdk-java:${alipaySdkVersion}"
}
package net.dreamlu.mica.social.config;
import lombok.*;
/**
* JustAuth配置类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AuthConfig {
/**
* 客户端id:对应个平台的appKey
*/
private String clientId;
/**
* 客户端Secret:对应个平台的appSecret
*/
private String clientSecret;
/**
* 登录成功后的回调地址
*/
private String redirectUri;
/**
* 支付宝公钥:当选择支付宝登录时,该值可用
*/
private String alipayPublicKey;
}
package net.dreamlu.mica.social.config;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.request.ResponseStatus;
/**
* 各api需要的url, 用枚举类分平台类型管理
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.0
*/
public enum AuthSource {
/**
* Github
*/
GITHUB {
@Override
public String authorize() {
return "https://github.com/login/oauth/authorize";
}
@Override
public String accessToken() {
return "https://github.com/login/oauth/access_token";
}
@Override
public String userInfo() {
return "https://api.github.com/user";
}
},
/**
* 新浪微博
*/
WEIBO {
@Override
public String authorize() {
return "https://api.weibo.com/oauth2/authorize";
}
@Override
public String accessToken() {
return "https://api.weibo.com/oauth2/access_token";
}
@Override
public String userInfo() {
return "https://api.weibo.com/2/users/show.json";
}
},
/**
* gitee
*/
GITEE {
@Override
public String authorize() {
return "https://gitee.com/oauth/authorize";
}
@Override
public String accessToken() {
return "https://gitee.com/oauth/token";
}
@Override
public String userInfo() {
return "https://gitee.com/api/v5/user";
}
},
/**
* 钉钉
*/
DINGTALK {
@Override
public String authorize() {
return "https://oapi.dingtalk.com/connect/qrconnect";
}
@Override
public String accessToken() {
throw new AuthException(ResponseStatus.UNSUPPORTED);
}
@Override
public String userInfo() {
return "https://oapi.dingtalk.com/sns/getuserinfo_bycode";
}
},
/**
* 百度
*/
BAIDU {
@Override
public String authorize() {
return "https://openapi.baidu.com/oauth/2.0/authorize";
}
@Override
public String accessToken() {
return "https://openapi.baidu.com/oauth/2.0/token";
}
@Override
public String userInfo() {
return "https://openapi.baidu.com/rest/2.0/passport/users/getInfo";
}
@Override
public String revoke() {
return "https://openapi.baidu.com/rest/2.0/passport/auth/revokeAuthorization";
}
},
/**
* csdn
*/
CSDN {
@Override
public String authorize() {
return "https://api.csdn.net/oauth2/authorize";
}
@Override
public String accessToken() {
return "https://api.csdn.net/oauth2/access_token";
}
@Override
public String userInfo() {
return "https://api.csdn.net/user/getinfo";
}
},
/**
* Coding
*/
CODING {
@Override
public String authorize() {
return "https://coding.net/oauth_authorize.html";
}
@Override
public String accessToken() {
return "https://coding.net/api/oauth/access_token";
}
@Override
public String userInfo() {
return "https://coding.net/api/account/current_user";
}
},
/**
* 腾讯云开发者平台(coding升级后就变成腾讯云开发者平台了)
*/
TENCENT_CLOUD {
@Override
public String authorize() {
return "https://dev.tencent.com/oauth_authorize.html";
}
@Override
public String accessToken() {
return "https://dev.tencent.com/api/oauth/access_token";
}
@Override
public String userInfo() {
return "https://dev.tencent.com/api/account/current_user";
}
},
/**
* oschina 开源中国
*/
OSCHINA {
@Override
public String authorize() {
return "https://www.oschina.net/action/oauth2/authorize";
}
@Override
public String accessToken() {
return "https://www.oschina.net/action/openapi/token";
}
@Override
public String userInfo() {
return "https://www.oschina.net/action/openapi/user";
}
},
/**
* 支付宝
*/
ALIPAY {
@Override
public String authorize() {
return "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm";
}
@Override
public String accessToken() {
return "https://openapi.alipay.com/gateway.do";
}
@Override
public String userInfo() {
return "https://openapi.alipay.com/gateway.do";
}
},
/**
* QQ
*/
QQ {
@Override
public String authorize() {
return "https://graph.qq.com/oauth2.0/authorize";
}
@Override
public String accessToken() {
return "https://graph.qq.com/oauth2.0/token";
}
@Override
public String userInfo() {
return "https://graph.qq.com/user/get_user_info";
}
},
/**
* 微信
*/
WECHAT {
@Override
public String authorize() {
return "https://open.weixin.qq.com/connect/qrconnect";
}
@Override
public String accessToken() {
return "https://api.weixin.qq.com/sns/oauth2/access_token";
}
@Override
public String userInfo() {
return "https://api.weixin.qq.com/sns/userinfo";
}
@Override
public String refresh() {
return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
}
},
/**
* 淘宝
*/
TAOBAO {
@Override
public String authorize() {
return "https://oauth.taobao.com/authorize";
}
@Override
public String accessToken() {
return "https://oauth.taobao.com/token";
}
@Override
public String userInfo() {
throw new AuthException(ResponseStatus.UNSUPPORTED);
}
},
/**
* Google
*/
GOOGLE {
@Override
public String authorize() {
return "https://accounts.google.com/o/oauth2/v2/auth";
}
@Override
public String accessToken() {
return "https://www.googleapis.com/oauth2/v4/token";
}
@Override
public String userInfo() {
return "https://oauth2.googleapis.com/tokeninfo";
}
},
/**
* Facebook
*/
FACEBOOK {
@Override
public String authorize() {
return "https://www.facebook.com/v3.3/dialog/oauth";
}
@Override
public String accessToken() {
return "https://graph.facebook.com/v3.3/oauth/access_token";
}
@Override
public String userInfo() {
return "https://graph.facebook.com/v3.3/me";
}
},
/**
* 抖音
*/
DOUYIN {
@Override
public String authorize() {
return "https://open.douyin.com/platform/oauth/connect";
}
@Override
public String accessToken() {
return "https://open.douyin.com/oauth/access_token";
}
@Override
public String userInfo() {
return "https://open.douyin.com/oauth/userinfo";
}
@Override
public String refresh() {
return "https://open.douyin.com/oauth/refresh_token";
}
},
/**
* 领英
*/
LINKEDIN {
@Override
public String authorize() {
return "https://www.linkedin.com/oauth/v2/authorization";
}
@Override
public String accessToken() {
return "https://www.linkedin.com/oauth/v2/accessToken";
}
@Override
public String userInfo() {
return "https://api.linkedin.com/v2/me";
}
@Override
public String refresh() {
return "https://www.linkedin.com/oauth/v2/accessToken";
}
},
/**
* 微软
*/
MICROSOFT {
@Override
public String authorize() {
return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
}
@Override
public String accessToken() {
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
}
@Override
public String userInfo() {
return "https://graph.microsoft.com/v1.0/me";
}
@Override
public String refresh() {
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
}
},
/**
* 小米
*/
MI {
@Override
public String authorize() {
return "https://account.xiaomi.com/oauth2/authorize";
}
@Override
public String accessToken() {
return "https://account.xiaomi.com/oauth2/token";
}
@Override
public String userInfo() {
return "https://open.account.xiaomi.com/user/profile";
}
@Override
public String refresh() {
return "https://account.xiaomi.com/oauth2/token";
}
},
/**
* 今日头条
*/
TOUTIAO {
@Override
public String authorize() {
return "https://open.snssdk.com/auth/authorize";
}
@Override
public String accessToken() {
return "https://open.snssdk.com/auth/token";
}
@Override
public String userInfo() {
return "https://open.snssdk.com/data/user_profile";
}
};
/**
* 授权的api
*
* @return url
*/
public abstract String authorize();
/**
* 获取accessToken的api
*
* @return url
*/
public abstract String accessToken();
/**
* 获取用户信息的api
*
* @return url
*/
public abstract String userInfo();
/**
* 取消授权的api
*
* @return url
*/
public String revoke() {
throw new AuthException(ResponseStatus.UNSUPPORTED);
}
/**
* 刷新授权的api
*
* @return url
*/
public String refresh() {
throw new AuthException(ResponseStatus.UNSUPPORTED);
}
}
package net.dreamlu.mica.social.exception;
import net.dreamlu.mica.core.utils.StringPool;
import net.dreamlu.mica.social.request.ResponseStatus;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
public class AuthException extends RuntimeException {
private int errorCode;
private String errorMsg;
public AuthException(String errorMsg) {
this(ResponseStatus.FAILURE.getCode(), errorMsg);
}
public AuthException(int errorCode, String errorMsg) {
super(errorCode + StringPool.COLON + errorMsg);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public AuthException(ResponseStatus status) {
super(status.getMsg());
}
public AuthException(String message, Throwable cause) {
super(message, cause);
}
public int getErrorCode() {
return errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
}
package net.dreamlu.mica.social.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.dreamlu.mica.core.utils.StringUtil;
/**
* 百度授权登录时的异常状态码
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
@AllArgsConstructor
public enum AuthBaiduErrorCode {
/**
* 百度授权登录时的异常状态码
*/
OK("ok", "ok", "ok"),
INVALID_REQUEST("invalid_request", "invalid refresh token", "请求缺少某个必需参数,包含一个不支持的参数或参数值,或者格式不正确。"),
INVALID_CLIENT("invalid_client", "unknown client id", "client_id”、“client_secret”参数无效。"),
INVALID_GRANT("invalid_grant", "The provided authorization grant is revoked", "提供的Access Grant是无效的、过期的或已撤销的,例如,Authorization Code无效(一个授权码只能使用一次)、Refresh Token无效、redirect_uri与获取Authorization Code时提供的不一致、Devie Code无效(一个设备授权码只能使用一次)等。"),
UNAUTHORIZED_CLIENT("unauthorized_client", "The client is not authorized to use this authorization grant type", "应用没有被授权,无法使用所指定的grant_type。"),
UNSUPPORTED_GRANT_TYPE("unsupported_grant_type", "The authorization grant type is not supported", "“grant_type”百度OAuth2.0服务不支持该参数。"),
INVALID_SCOPE("invalid_scope", "The requested scope is exceeds the scope granted by the resource owner", "请求的“scope”参数是无效的、未知的、格式不正确的、或所请求的权限范围超过了数据拥有者所授予的权限范围。"),
EXPIRED_TOKEN("expired_token", "refresh token has been used", "提供的Refresh Token已过期"),
REDIRECT_URI_MISMATCH("redirect_uri_mismatch", "Invalid redirect uri", "“redirect_uri”所在的根域与开发者注册应用时所填写的根域名不匹配。"),
UNSUPPORTED_RESPONSE_TYPE("unsupported_response_type", "The response type is not supported", "“response_type”参数值不为百度OAuth2.0服务所支持,或者应用已经主动禁用了对应的授权模式"),
SLOW_DOWN("slow_down", "The device is polling too frequently", "Device Flow中,设备通过Device Code换取Access Token的接口过于频繁,两次尝试的间隔应大于5秒。"),
AUTHORIZATION_PENDING("authorization_pending", "User has not yet completed the authorization", "Device Flow中,用户还没有对Device Code完成授权操作。"),
AUTHORIZATION_DECLINED("authorization_declined", "User has declined the authorization", "Device Flow中,用户拒绝了对Device Code的授权操作。"),
INVALID_REFERER("invalid_referer", "Invalid Referer", "Implicit Grant模式中,浏览器请求的Referer与根域名绑定不匹配");
private String code;
private String msg;
private String desc;
public static AuthBaiduErrorCode getErrorCode(String code) {
if (StringUtil.isBlank(code)) {
return OK;
}
AuthBaiduErrorCode[] errorCodes = AuthBaiduErrorCode.values();
for (AuthBaiduErrorCode errorCode : errorCodes) {
if (code.equalsIgnoreCase(errorCode.getCode())) {
return errorCode;
}
}
return OK;
}
}
package net.dreamlu.mica.social.model;
import lombok.Builder;
import lombok.Data;
import net.dreamlu.mica.social.request.ResponseStatus;
/**
* JustAuth统一授权响应类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Builder
@Data
public class AuthResponse<T> {
/**
* 授权响应状态码
*/
private int code;
/**
* 授权响应信息
*/
private String msg;
/**
* 授权响应数据,当且仅当 code = 2000 时返回
*/
private T data;
/**
* 是否请求成功
*
* @return true or false
*/
public boolean ok() {
return this.code == ResponseStatus.SUCCESS.getCode();
}
}
package net.dreamlu.mica.social.model;
import lombok.Builder;
import lombok.Data;
/**
* 授权所需的token
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Data
@Builder
public class AuthToken {
private String accessToken;
private int expireIn;
private String refreshToken;
private String uid;
private String openId;
private String accessCode;
/**
* Google附带属性
*/
private String scope;
private String tokenType;
private String idToken;
/**
* 小米附带属性
*/
private String macAlgorithm;
private String macKey;
}
package net.dreamlu.mica.social.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 今日头条授权登录时的异常状态码
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
@AllArgsConstructor
public enum AuthToutiaoErrorCode {
EC0(0, "接口调用成功"),
EC1(1, "API配置错误,未传入Client Key"),
EC2(2, "API配置错误,Client Key错误,请检查是否和开放平台的ClientKey一致"),
EC3(3, "没有授权信息"),
EC4(4, "响应类型错误"),
EC5(5, "授权类型错误"),
EC6(6, "client_secret错误"),
EC7(7, "authorize_code过期"),
EC8(8, "指定url的scheme不是https"),
EC9(9, "接口内部错误,请联系头条技术"),
EC10(10, "access_token过期"),
EC11(11, "缺少access_token"),
EC12(12, "参数缺失"),
EC13(13, "url错误"),
EC21(21, "域名与登记域名不匹配"),
EC999(999, "未知错误,请联系头条技术"),
;
private int code;
private String desc;
public static AuthToutiaoErrorCode getErrorCode(int errorCode) {
AuthToutiaoErrorCode[] errorCodes = AuthToutiaoErrorCode.values();
for (AuthToutiaoErrorCode code : errorCodes) {
if (code.getCode() == errorCode) {
return code;
}
}
return EC999;
}
}
package net.dreamlu.mica.social.model;
import lombok.Builder;
import lombok.Data;
import net.dreamlu.mica.social.config.AuthSource;
/**
* 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Builder
@Data
public class AuthUser {
/**
* 用户名
*/
private String username;
/**
* 用户昵称
*/
private String nickname;
/**
* 用户头像
*/
private String avatar;
/**
* 用户网址
*/
private String blog;
/**
* 所在公司
*/
private String company;
/**
* 位置
*/
private String location;
/**
* 用户邮箱
*/
private String email;
/**
* 用户备注(各平台中的用户个人介绍)
*/
private String remark;
/**
* 性别
*/
private AuthUserGender gender;
/**
* 用户来源
*/
private AuthSource source;
/**
* 用户授权的token信息
*/
private AuthToken token;
/**
* 用户第三方系统的唯一id。在调用方集成改组件时,可以用uuid + source唯一确定一个用户
*/
private String uuid;
}
package net.dreamlu.mica.social.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 用户性别
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
@AllArgsConstructor
public enum AuthUserGender {
MALE(1, "男"), FEMALE(0, "女"), UNKNOW(-1, "");
private int code;
private String desc;
public static AuthUserGender getRealGender(String code) {
if (code == null) {
return UNKNOW;
}
String[] males = {"m", "男", "1", "male", "F"};
if (Arrays.asList(males).contains(code)) {
return MALE;
}
String[] females = {"f", "女", "0", "female"};
if (Arrays.asList(females).contains(code)) {
return FEMALE;
}
return UNKNOW;
}
}
package net.dreamlu.mica.social.request;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import net.dreamlu.mica.core.utils.StringUtil;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 支付宝登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthAlipayRequest extends BaseAuthRequest {
private static final AuthSource API_URL = AuthSource.ALIPAY;
private AlipayClient alipayClient;
public AuthAlipayRequest(AuthConfig config) {
super(config, API_URL);
this.alipayClient = new DefaultAlipayClient(API_URL.accessToken(), config.getClientId(), config.getClientSecret(), "json", "UTF-8", config.getAlipayPublicKey(), "RSA2");
}
@Override
public String authorize() {
return UrlBuilder.getAlipayAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
request.setGrantType("authorization_code");
request.setCode(code);
AlipaySystemOauthTokenResponse response = null;
try {
response = this.alipayClient.execute(request);
} catch (Exception e) {
throw new AuthException("Unable to get token from alipay using code [" + code + "]", e);
}
if (!response.isSuccess()) {
throw new AuthException(response.getSubMsg());
}
return AuthToken.builder()
.accessToken(response.getAccessToken())
.uid(response.getUserId())
.expireIn(Integer.parseInt(response.getExpiresIn()))
.refreshToken(response.getRefreshToken())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
AlipayUserInfoShareRequest request = new AlipayUserInfoShareRequest();
AlipayUserInfoShareResponse response = null;
try {
response = this.alipayClient.execute(request, accessToken);
} catch (AlipayApiException e) {
throw new AuthException(e.getErrMsg(), e);
}
if (!response.isSuccess()) {
throw new AuthException(response.getSubMsg());
}
String province = response.getProvince(),
city = response.getCity();
return AuthUser.builder()
.uuid(response.getUserId())
.username(StringUtil.isBlank(response.getUserName()) ? response.getNickName() : response.getUserName())
.nickname(response.getNickName())
.avatar(response.getAvatar())
.location(String.format("%s %s", StringUtil.isBlank(province) ? "" : province, StringUtil.isBlank(city) ? "" : city))
.gender(AuthUserGender.getRealGender(response.getGender()))
.token(authToken)
.source(API_URL)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.*;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 百度账号登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthBaiduRequest extends BaseAuthRequest {
public AuthBaiduRequest(AuthConfig config) {
super(config, AuthSource.BAIDU);
}
@Override
public String authorize() {
return UrlBuilder.getBaiduAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getBaiduAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
JsonNode jsonNode = HttpRequest.post(accessTokenUrl)
.execute()
.asJsonNode();
AuthBaiduErrorCode errorCode = AuthBaiduErrorCode.getErrorCode(jsonNode.get("error").asText());
if (!AuthBaiduErrorCode.OK.equals(errorCode)) {
throw new AuthException(errorCode.getDesc());
}
return AuthToken.builder()
.accessToken(jsonNode.get("access_token").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode jsonNode = HttpRequest.get(UrlBuilder.getBaiduUserInfoUrl(accessToken))
.execute()
.asJsonNode();
AuthBaiduErrorCode errorCode = AuthBaiduErrorCode.getErrorCode(jsonNode.get("error").asText());
if (!AuthBaiduErrorCode.OK.equals(errorCode)) {
throw new AuthException(errorCode.getDesc());
}
return AuthUser.builder()
.uuid(jsonNode.get("userid").asText())
.username(jsonNode.get("username").asText())
.nickname(jsonNode.get("username").asText())
.gender(AuthUserGender.getRealGender(jsonNode.get("sex").asText()))
.token(authToken)
.source(AuthSource.BAIDU)
.build();
}
@Override
public AuthResponse revoke(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode jsonNode = HttpRequest.get(UrlBuilder.getBaiduRevokeUrl(accessToken))
.execute()
.asJsonNode();
if (jsonNode.has("error_code")) {
return AuthResponse.builder()
.code(ResponseStatus.FAILURE.getCode())
.msg(jsonNode.get("error_msg").asText())
.build();
}
ResponseStatus status = jsonNode.get("result").asInt() == 1 ? ResponseStatus.SUCCESS : ResponseStatus.FAILURE;
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* Cooding登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthCodingRequest extends BaseAuthRequest {
public AuthCodingRequest(AuthConfig config) {
super(config, AuthSource.CODING);
}
@Override
public String authorize() {
return UrlBuilder.getCodingAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getCodingAccessTokenUrl(config.getClientId(), config.getClientSecret(), code);
JsonNode jsonNode = HttpRequest.get(accessTokenUrl)
.execute()
.asJsonNode();
if (jsonNode.get("code").asInt() != 0) {
throw new AuthException("Unable to get token from coding using code [" + code + "]");
}
return AuthToken.builder()
.accessToken(jsonNode.get("access_token").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode jsonNode = HttpRequest.get(UrlBuilder.getCodingUserInfoUrl(accessToken))
.execute()
.asJsonNode();
if (jsonNode.get("code").asInt() != 0) {
throw new AuthException(jsonNode.get("msg").asText());
}
JsonNode data = jsonNode.get("data");
return AuthUser.builder()
.uuid(data.get("id").asText())
.username(data.get("name").asText())
.avatar("https://coding.net/" + data.get("avatar").asText())
.blog("https://coding.net/" + data.get("path").asText())
.nickname(data.get("name").asText())
.company(data.get("company").asText())
.location(data.get("location").asText())
.gender(AuthUserGender.getRealGender(data.get("sex").asText()))
.email(data.get("email").asText())
.remark(data.get("slogan").asText())
.token(authToken)
.source(AuthSource.CODING)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* CSDN登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthCsdnRequest extends BaseAuthRequest {
public AuthCsdnRequest(AuthConfig config) {
super(config, AuthSource.CSDN);
}
@Override
public String authorize() {
return UrlBuilder.getCsdnAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getCsdnAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
JsonNode accessTokenObject = HttpRequest.post(accessTokenUrl)
.execute()
.asJsonNode();
if (accessTokenObject.has("error_code")) {
throw new AuthException("Unable to get token from csdn using code [" + code + "]");
}
return AuthToken.builder()
.accessToken(accessTokenObject.get("access_token").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode object = HttpRequest.get(UrlBuilder.getCsdnUserInfoUrl(accessToken))
.execute()
.asJsonNode();
if (object.has("error_code")) {
throw new AuthException(object.get("error").asText());
}
return AuthUser.builder()
.uuid(object.get("username").asText())
.username(object.get("username").asText())
.remark(object.get("description").asText())
.blog(object.get("website").asText())
.token(authToken)
.source(AuthSource.CSDN)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthDingTalkErrorCode;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.GlobalAuthUtil;
import net.dreamlu.mica.social.utils.UrlBuilder;
import java.util.HashMap;
import java.util.Map;
/**
* 钉钉登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthDingTalkRequest extends BaseAuthRequest {
public AuthDingTalkRequest(AuthConfig config) {
super(config, AuthSource.DINGTALK);
}
@Override
public String authorize() {
return UrlBuilder.getDingTalkQrConnectUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
return AuthToken.builder()
.accessCode(code)
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String code = authToken.getAccessCode();
// 根据timestamp, appSecret计算签名值
String stringToSign = System.currentTimeMillis() + "";
String urlEncodeSignature = GlobalAuthUtil.generateDingTalkSignature(config.getClientSecret(), stringToSign);
String dingTalkUserInfoUrl = UrlBuilder.getDingTalkUserInfoUrl(urlEncodeSignature, stringToSign, config.getClientId());
Map<String, Object> bodyJson = new HashMap<>(1);
bodyJson.put("tmp_auth_code", code);
JsonNode object = HttpRequest.post(dingTalkUserInfoUrl)
.bodyJson(bodyJson)
.execute()
.asJsonNode();
AuthDingTalkErrorCode errorCode = AuthDingTalkErrorCode.getErrorCode(object.get("errcode").asInt());
if (!AuthDingTalkErrorCode.EC0.equals(errorCode)) {
throw new AuthException(errorCode.getDesc());
}
JsonNode userInfo = object.get("user_info");
return AuthUser.builder()
.uuid(userInfo.get("openid").asText())
.nickname(userInfo.get("nick").asText())
.username(userInfo.get("nick").asText())
.source(AuthSource.DINGTALK)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthResponse;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 抖音登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthDouyinRequest extends BaseAuthRequest {
public AuthDouyinRequest(AuthConfig config) {
super(config, AuthSource.DOUYIN);
}
@Override
public String authorize() {
return UrlBuilder.getDouyinAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getDouyinAccessTokenUrl(config.getClientId(), config.getClientSecret(), code);
return this.getToken(accessTokenUrl);
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
String openId = authToken.getOpenId();
JsonNode object = HttpRequest.get(UrlBuilder.getDouyinUserInfoUrl(accessToken, openId))
.execute()
.asJsonNode();
JsonNode userInfoObject = this.checkResponse(object);
return AuthUser.builder()
.uuid(userInfoObject.get("open_id").asText())
.username(userInfoObject.get("nickname").asText())
.nickname(userInfoObject.get("nickname").asText())
.avatar(userInfoObject.get("avatar").asText())
.token(authToken)
.source(AuthSource.DOUYIN)
.build();
}
@Override
public AuthResponse refresh(AuthToken oldToken) {
String refreshTokenUrl = UrlBuilder.getDouyinRefreshUrl(config.getClientId(), oldToken.getRefreshToken());
return AuthResponse.builder()
.code(ResponseStatus.SUCCESS.getCode())
.data(this.getToken(refreshTokenUrl))
.build();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
* @return 实际请求数据的json对象
*/
private JsonNode checkResponse(JsonNode object) {
String message = object.get("message").asText();
JsonNode data = object.get("data");
int errorCode = data.get("error_code").asInt();
if ("error".equals(message) || errorCode != 0) {
throw new AuthException(errorCode, data.get("description").asText());
}
return data;
}
/**
* 获取token,适用于获取access_token和刷新token
*
* @param accessTokenUrl 实际请求token的地址
* @return token对象
*/
private AuthToken getToken(String accessTokenUrl) {
JsonNode object = HttpRequest.post(accessTokenUrl)
.execute()
.asJsonNode();
JsonNode accessTokenObject = this.checkResponse(object);
return AuthToken.builder()
.accessToken(accessTokenObject.get("access_token").asText())
.openId(accessTokenObject.get("open_id").asText())
.expireIn(accessTokenObject.get("expires_in").asInt())
.refreshToken(accessTokenObject.get("refresh_token").asText())
.scope(accessTokenObject.get("scope").asText())
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* Facebook登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthFacebookRequest extends BaseAuthRequest {
public AuthFacebookRequest(AuthConfig config) {
super(config, AuthSource.FACEBOOK);
}
@Override
public String authorize() {
return UrlBuilder.getFacebookAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getFacebookAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
JsonNode object = HttpRequest.post(accessTokenUrl)
.execute()
.asJsonNode();
if (object.has("error")) {
throw new AuthException(object.get("error").get("message").asText());
}
return AuthToken.builder()
.accessToken(object.get("access_token").asText())
.expireIn(object.get("expires_in").asInt())
.tokenType(object.get("token_type").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode object = HttpRequest.get(UrlBuilder.getFacebookUserInfoUrl(accessToken))
.execute()
.asJsonNode();
if (object.has("error")) {
throw new AuthException(object.get("error").get("message").asText());
}
return AuthUser.builder()
.uuid(object.get("id").asText())
.username(object.get("name").asText())
.nickname(object.get("name").asText())
.avatar(object.get("/picture/data/url").asText())
.location(object.get("locale").asText())
.email(object.get("email").asText())
.gender(AuthUserGender.getRealGender(object.get("gender").asText()))
.token(authToken)
.source(AuthSource.FACEBOOK)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* Gitee登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthGiteeRequest extends BaseAuthRequest {
public AuthGiteeRequest(AuthConfig config) {
super(config, AuthSource.GITEE);
}
@Override
public String authorize() {
return UrlBuilder.getGiteeAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getGiteeAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
JsonNode accessTokenObject = HttpRequest.post(accessTokenUrl)
.execute()
.asJsonNode();
if (accessTokenObject.has("error")) {
throw new AuthException("Unable to get token from gitee using code [" + code + "]");
}
return AuthToken.builder()
.accessToken(accessTokenObject.get("access_token").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode object = HttpRequest.get(UrlBuilder.getGiteeUserInfoUrl(accessToken))
.execute()
.asJsonNode();
return AuthUser.builder()
.uuid(object.get("id").asText())
.username(object.get("login").asText())
.avatar(object.get("avatar_url").asText())
.blog(object.get("blog").asText())
.nickname(object.get("name").asText())
.company(object.get("company").asText())
.location(object.get("address").asText())
.email(object.get("email").asText())
.remark(object.get("bio").asText())
.token(authToken)
.source(AuthSource.GITEE)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.GlobalAuthUtil;
import net.dreamlu.mica.social.utils.UrlBuilder;
import java.util.Map;
/**
* Github登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthGithubRequest extends BaseAuthRequest {
public AuthGithubRequest(AuthConfig config) {
super(config, AuthSource.GITHUB);
}
@Override
public String authorize() {
return UrlBuilder.getGithubAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getGithubAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
String result = HttpRequest.post(accessTokenUrl)
.execute()
.asString();
Map<String, String> res = GlobalAuthUtil.parseStringToMap(result);
if (res.containsKey("error")) {
throw new AuthException(res.get("error") + ":" + res.get("error_description"));
}
return AuthToken.builder()
.accessToken(res.get("access_token"))
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode object = HttpRequest.get(UrlBuilder.getGithubUserInfoUrl(accessToken))
.execute()
.asJsonNode();
return AuthUser.builder()
.uuid(object.get("id").asText())
.username(object.get("login").asText())
.avatar(object.get("avatar_url").asText())
.blog(object.get("blog").asText())
.nickname(object.get("name").asText())
.company(object.get("company").asText())
.location(object.get("location").asText())
.email(object.get("email").asText())
.remark(object.get("bio").asText())
.token(authToken)
.source(AuthSource.GITHUB)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* Google登录
*
* @author yangkai.shen (https://xkcoding.com), L.cm
* @version 1.3
* @since 1.3
*/
public class AuthGoogleRequest extends BaseAuthRequest {
public AuthGoogleRequest(AuthConfig config) {
super(config, AuthSource.GOOGLE);
}
@Override
public String authorize() {
return UrlBuilder.getGoogleAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getGoogleAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config
.getRedirectUri());
JsonNode object = HttpRequest.post(accessTokenUrl)
.execute()
.asJsonNode();
if (object.has("error") || object.has("error_description")) {
throw new AuthException("get google access_token has error:[" + object.get("error").asText() + "], error_description:[" + object
.get("error_description").asText() + "]");
}
return AuthToken.builder()
.accessToken(object.get("access_token").asText())
.expireIn(object.get("expires_in").asInt())
.scope(object.get("scope").asText())
.tokenType(object.get("token_type").asText())
.idToken(object.get("id_token").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getIdToken();
JsonNode object = HttpRequest.get(UrlBuilder.getGoogleUserInfoUrl(accessToken))
.execute()
.asJsonNode();
return AuthUser.builder()
.uuid(object.get("sub").asText())
.username(object.get("name").asText())
.avatar(object.get("picture").asText())
.nickname(object.get("name").asText())
.location(object.get("locale").asText())
.email(object.get("email").asText())
.token(authToken)
.source(AuthSource.GOOGLE)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.core.utils.StringUtil;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthResponse;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 领英登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthLinkedinRequest extends BaseAuthRequest {
public AuthLinkedinRequest(AuthConfig config) {
super(config, AuthSource.LINKEDIN);
}
@Override
public String authorize() {
return UrlBuilder.getLinkedinAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getLinkedinAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
return this.getToken(accessTokenUrl);
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode userInfoObject = HttpRequest.get(UrlBuilder.getLinkedinUserInfoUrl())
.addHeader("Host", "api.linkedin.com")
.addHeader("Connection", "Keep-Alive")
.addHeader("Authorization", "Bearer " + accessToken)
.execute()
.asJsonNode();
this.checkResponse(userInfoObject);
// 组装用户名
String firstName, lastName;
// 获取firstName
if (userInfoObject.has("localizedFirstName")) {
firstName = userInfoObject.get("localizedFirstName").asText();
} else {
firstName = getUserName(userInfoObject, "firstName");
}
// 获取lastName
if (userInfoObject.has("localizedLastName")) {
lastName = userInfoObject.get("localizedLastName").asText();
} else {
lastName = getUserName(userInfoObject, "lastName");
}
String userName = firstName + " " + lastName;
// 获取用户头像
String avatar = userInfoObject.get("/profilePicture/displayImage~/elements/0/identifiers/0/identifier").asText();
// 获取用户邮箱地址
String email = this.getUserEmail(accessToken);
return AuthUser.builder()
.uuid(userInfoObject.get("id").asText())
.username(userName)
.nickname(userName)
.avatar(avatar)
.email(email)
.token(authToken)
.source(AuthSource.LINKEDIN)
.build();
}
private String getUserEmail(String accessToken) {
return HttpRequest.get("https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))")
.addHeader("Host", "api.linkedin.com")
.addHeader("Connection", "Keep-Alive")
.addHeader("Authorization", "Bearer " + accessToken)
.execute()
.asJsonNode()
.at("/elements/0/handle~/emailAddress")
.asText();
}
private String getUserName(JsonNode userInfoObject, String nameKey) {
String firstName;
JsonNode firstNameObj = userInfoObject.get(nameKey);
JsonNode localizedObj = firstNameObj.get("localized");
JsonNode preferredLocaleObj = firstNameObj.get("preferredLocale");
firstName = localizedObj.get(preferredLocaleObj.get("language").asText() + "_" + preferredLocaleObj.get("country").asText()).asText();
return firstName;
}
@Override
public AuthResponse refresh(AuthToken oldToken) {
if (StringUtil.isBlank(oldToken.getRefreshToken())) {
throw new AuthException(ResponseStatus.UNSUPPORTED);
}
String refreshTokenUrl = UrlBuilder.getLinkedinRefreshUrl(config.getClientId(), config.getClientSecret(), oldToken.getRefreshToken());
return AuthResponse.builder()
.code(ResponseStatus.SUCCESS.getCode())
.data(this.getToken(refreshTokenUrl))
.build();
}
private void checkResponse(JsonNode userInfoObject) {
if (userInfoObject.has("error")) {
throw new AuthException(userInfoObject.get("error_description").asText());
}
}
/**
* 获取token,适用于获取access_token和刷新token
*
* @param accessTokenUrl 实际请求token的地址
* @return token对象
*/
private AuthToken getToken(String accessTokenUrl) {
JsonNode accessTokenObject = HttpRequest.post(accessTokenUrl)
.addHeader("Host", "www.linkedin.com")
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.execute()
.asJsonNode();
this.checkResponse(accessTokenObject);
return AuthToken.builder()
.accessToken(accessTokenObject.get("access_token").asText())
.expireIn(accessTokenObject.get("expires_in").asInt())
.refreshToken(accessTokenObject.get("refresh_token").asText())
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.core.utils.JsonUtil;
import net.dreamlu.mica.core.utils.StringPool;
import net.dreamlu.mica.core.utils.StringUtil;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthResponse;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.UrlBuilder;
import java.text.MessageFormat;
/**
* 小米登录
*
* @author yangkai.shen (https://xkcoding.com), L.cm
* @version 1.5
* @since 1.5
*/
public class AuthMiRequest extends BaseAuthRequest {
private static final String PREFIX = "&&&START&&&";
public AuthMiRequest(AuthConfig config) {
super(config, AuthSource.MI);
}
@Override
public String authorize() {
return UrlBuilder.getMiAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getMiAccessTokenUrl(config.getClientId(), config.getClientSecret(), config.getRedirectUri(), code);
return getToken(accessTokenUrl);
}
private AuthToken getToken(String accessTokenUrl) {
String result = HttpRequest.get(accessTokenUrl)
.execute()
.asString();
String jsonStr = StringUtil.replace(result, PREFIX, StringPool.EMPTY);
JsonNode object = JsonUtil.readTree(jsonStr);
if (object.has("error")) {
throw new AuthException(object.get("error_description").asText());
}
return AuthToken.builder()
.accessToken(object.get("access_token").asText())
.expireIn(object.get("expires_in").asInt())
.scope(object.get("scope").asText())
.tokenType(object.get("token_type").asText())
.refreshToken(object.get("refresh_token").asText())
.openId(object.get("openId").asText())
.macAlgorithm(object.get("mac_algorithm").asText())
.macKey(object.get("mac_key").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
// 获取用户信息
JsonNode userProfile = HttpRequest.get(UrlBuilder.getMiUserInfoUrl(config.getClientId(), authToken.getAccessToken()))
.execute()
.asJsonNode();
if ("error".equalsIgnoreCase(userProfile.get("result").asText())) {
throw new AuthException(userProfile.get("description").asText());
}
JsonNode user = userProfile.get("data");
AuthUser authUser = AuthUser.builder()
.uuid(authToken.getOpenId())
.username(user.get("miliaoNick").asText())
.nickname(user.get("miliaoNick").asText())
.avatar(user.get("miliaoIcon").asText())
.email(user.get("mail").asText())
.token(authToken)
.source(AuthSource.MI)
.build();
// 获取用户邮箱手机号等信息
String emailPhoneUrl = MessageFormat.format("{0}?clientId={1}&token={2}", "https://open.account.xiaomi.com/user/phoneAndEmail", config
.getClientId(), authToken.getAccessToken());
JsonNode userEmailPhone = HttpRequest.get(emailPhoneUrl)
.execute()
.asJsonNode();
if ("error".equalsIgnoreCase(userEmailPhone.get("result").asText())) {
JsonNode emailPhone = userEmailPhone.get("data");
authUser.setEmail(emailPhone.get("email").asText());
}
return authUser;
}
/**
* 刷新access token (续期)
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
@Override
public AuthResponse refresh(AuthToken authToken) {
String miRefreshUrl = UrlBuilder.getMiRefreshUrl(config.getClientId(), config.getClientSecret(), config.getRedirectUri(), authToken.getRefreshToken());
return AuthResponse.builder().code(ResponseStatus.SUCCESS.getCode()).data(getToken(miRefreshUrl)).build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthResponse;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.GlobalAuthUtil;
import net.dreamlu.mica.social.utils.UrlBuilder;
import okhttp3.FormBody;
/**
* 微软登录
*
* @author yangkai.shen (https://xkcoding.com), L.cm
* @version 1.5
* @since 1.5
*/
public class AuthMicrosoftRequest extends BaseAuthRequest {
public AuthMicrosoftRequest(AuthConfig config) {
super(config, AuthSource.MICROSOFT);
}
@Override
public String authorize() {
return UrlBuilder.getMicrosoftAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getMicrosoftAccessTokenUrl(config.getClientId(), config.getClientSecret(), config
.getRedirectUri(), code);
return getToken(accessTokenUrl);
}
/**
* 获取token,适用于获取access_token和刷新token
*
* @param accessTokenUrl 实际请求token的地址
* @return token对象
*/
private AuthToken getToken(String accessTokenUrl) {
FormBody.Builder formBuilder = new FormBody.Builder();
GlobalAuthUtil.parseStringToMap(accessTokenUrl)
.forEach(formBuilder::add);
JsonNode object = HttpRequest.post(accessTokenUrl)
.addHeader("Host", "https://login.microsoftonline.com")
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.body(formBuilder.build())
.execute()
.asJsonNode();
this.checkResponse(object);
return AuthToken.builder()
.accessToken(object.get("access_token").asText())
.expireIn(object.get("expires_in").asInt())
.scope(object.get("scope").asText())
.tokenType(object.get("token_type").asText())
.refreshToken(object.get("refresh_token").asText())
.build();
}
private void checkResponse(JsonNode response) {
if (response.has("error")) {
throw new AuthException(response.get("error_description").asText());
}
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String token = authToken.getAccessToken();
String tokenType = authToken.getTokenType();
String jwt = tokenType + " " + token;
JsonNode object = HttpRequest.get(UrlBuilder.getMicrosoftUserInfoUrl())
.addHeader("Authorization", jwt)
.execute()
.asJsonNode();
return AuthUser.builder()
.uuid(object.get("id").asText())
.username(object.get("userPrincipalName").asText())
.nickname(object.get("displayName").asText())
.location(object.get("officeLocation").asText())
.email(object.get("mail").asText())
.token(authToken)
.source(AuthSource.MICROSOFT)
.build();
}
/**
* 刷新access token (续期)
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
@Override
public AuthResponse refresh(AuthToken authToken) {
String refreshTokenUrl = UrlBuilder.getMicrosoftRefreshUrl(config.getClientId(), config.getClientSecret(), config
.getRedirectUri(), authToken.getRefreshToken());
return AuthResponse.builder().code(ResponseStatus.SUCCESS.getCode()).data(getToken(refreshTokenUrl)).build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* oschina登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthOschinaRequest extends BaseAuthRequest {
public AuthOschinaRequest(AuthConfig config) {
super(config, AuthSource.OSCHINA);
}
@Override
public String authorize() {
return UrlBuilder.getOschinaAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getOschinaAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
JsonNode accessTokenObject = HttpRequest.post(accessTokenUrl)
.execute()
.asJsonNode();
if (accessTokenObject.has("error")) {
throw new AuthException("Unable to get token from oschina using code [" + code + "]");
}
return AuthToken.builder()
.accessToken(accessTokenObject.get("access_token").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode object = HttpRequest.get(UrlBuilder.getOschinaUserInfoUrl(accessToken))
.execute()
.asJsonNode();
if (object.has("error")) {
throw new AuthException(object.get("error_description").asText());
}
return AuthUser.builder()
.uuid(object.get("id").asText())
.username(object.get("name").asText())
.nickname(object.get("name").asText())
.avatar(object.get("avatar").asText())
.blog(object.get("url").asText())
.location(object.get("location").asText())
.gender(AuthUserGender.getRealGender(object.get("gender").asText()))
.email(object.get("email").asText())
.token(authToken)
.source(AuthSource.OSCHINA)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.http.HttpResponse;
import net.dreamlu.mica.core.utils.JsonUtil;
import net.dreamlu.mica.core.utils.StringUtil;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.GlobalAuthUtil;
import net.dreamlu.mica.social.utils.UrlBuilder;
import java.util.Map;
/**
* qq登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @author yangkai.shen (https://xkcoding.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthQqRequest extends BaseAuthRequest {
public AuthQqRequest(AuthConfig config) {
super(config, AuthSource.QQ);
}
@Override
public String authorize() {
return UrlBuilder.getQqAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getQqAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config
.getRedirectUri());
String response = HttpRequest.get(accessTokenUrl)
.execute()
.asString();
Map<String, String> accessTokenObject = GlobalAuthUtil.parseStringToMap(response);
if (!accessTokenObject.containsKey("access_token")) {
throw new AuthException("Unable to get token from qq using code [" + code + "]");
}
return AuthToken.builder()
.accessToken(accessTokenObject.get("access_token"))
.expireIn(Integer.valueOf(accessTokenObject.get("expires_in")))
.refreshToken(accessTokenObject.get("refresh_token"))
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
String openId = this.getOpenId(accessToken);
JsonNode object = HttpRequest.get(UrlBuilder.getQqUserInfoUrl(config.getClientId(), accessToken, openId))
.execute()
.asJsonNode();
if (object.get("ret").asInt() != 0) {
throw new AuthException(object.get("msg").asText());
}
String avatar = object.get("figureurl_qq_2").asText();
if (StringUtil.isBlank(avatar)) {
avatar = object.get("figureurl_qq_1").asText();
}
return AuthUser.builder()
.username(object.get("nickname").asText())
.nickname(object.get("nickname").asText())
.avatar(avatar)
.location(object.get("province") + "-" + object.get("city").asText())
.uuid(openId)
.gender(AuthUserGender.getRealGender(object.get("gender").asText()))
.token(authToken)
.source(AuthSource.QQ)
.build();
}
private String getOpenId(String accessToken) {
HttpResponse response = HttpRequest.get(UrlBuilder.getQqOpenidUrl("https://graph.qq.com/oauth2.0/me", accessToken))
.execute();
if (response.isOk()) {
String body = response.asString();
String removePrefix = StringUtil.replace(body, "callback(", "");
String removeSuffix = StringUtil.replace(removePrefix, ");", "");
String openId = StringUtil.trimWhitespace(removeSuffix);
JsonNode object = JsonUtil.readTree(openId);
if (object.has("openid")) {
return object.get("openid").asText();
}
throw new AuthException("Invalid openId");
}
throw new AuthException("Invalid openId");
}
}
package net.dreamlu.mica.social.request;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthResponse;
import net.dreamlu.mica.social.model.AuthToken;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public interface AuthRequest {
/**
* 返回认证url,可自行跳转页面
*
* @return 返回授权地址
*/
default String authorize() {
throw new AuthException(ResponseStatus.NOT_IMPLEMENTED);
}
/**
* 第三方登录
*
* @param code 通过authorize换回的code
* @return 返回登录成功后的用户信息
*/
default AuthResponse login(String code) {
throw new AuthException(ResponseStatus.NOT_IMPLEMENTED);
}
/**
* 撤销授权
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
default AuthResponse revoke(AuthToken authToken) {
throw new AuthException(ResponseStatus.NOT_IMPLEMENTED);
}
/**
* 刷新access token (续期)
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
default AuthResponse refresh(AuthToken authToken) {
throw new AuthException(ResponseStatus.NOT_IMPLEMENTED);
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.GlobalAuthUtil;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 淘宝登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthTaobaoRequest extends BaseAuthRequest {
public AuthTaobaoRequest(AuthConfig config) {
super(config, AuthSource.TAOBAO);
}
@Override
public String authorize() {
return UrlBuilder.getTaobaoAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
return AuthToken.builder()
.accessCode(code)
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessCode = authToken.getAccessCode();
JsonNode object = HttpRequest.post(UrlBuilder.getTaobaoAccessTokenUrl(this.config.getClientId(), this.config.getClientSecret(), accessCode, this.config.getRedirectUri()))
.execute()
.asJsonNode();
if (object.has("error")) {
throw new AuthException(ResponseStatus.FAILURE + ":" + object.get("error_description").asText());
}
authToken.setAccessToken(object.get("access_token").asText());
authToken.setRefreshToken(object.get("refresh_token").asText());
authToken.setExpireIn(object.get("expires_in").asInt());
authToken.setUid(object.get("taobao_user_id").asText());
authToken.setOpenId(object.get("taobao_open_uid").asText());
String nick = GlobalAuthUtil.urlDecode(object.get("taobao_user_nick").asText());
return AuthUser.builder()
.uuid(object.get("taobao_user_id").asText())
.username(nick)
.nickname(nick)
.gender(AuthUserGender.UNKNOW)
.token(authToken)
.source(AuthSource.TAOBAO)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 腾讯云登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthTencentCloudRequest extends BaseAuthRequest {
public AuthTencentCloudRequest(AuthConfig config) {
super(config, AuthSource.TENCENT_CLOUD);
}
@Override
public String authorize() {
return UrlBuilder.getTencentCloudAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getTencentCloudAccessTokenUrl(config.getClientId(), config.getClientSecret(), code);
JsonNode object = HttpRequest.get(accessTokenUrl)
.execute()
.asJsonNode();
if (object.get("code").asInt() != 0) {
throw new AuthException("Unable to get token from tencent cloud using code [" + code + "]: " + object.get("msg"));
}
return AuthToken.builder()
.accessToken(object.get("access_token").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
JsonNode object = HttpRequest.get(UrlBuilder.getTencentCloudUserInfoUrl(accessToken))
.execute()
.asJsonNode();
if (object.get("code").asInt() != 0) {
throw new AuthException(object.get("msg").asText());
}
JsonNode data = object.get("data");
return AuthUser.builder()
.uuid(data.get("id").asText())
.username(data.get("name").asText())
.avatar("https://dev.tencent.com/" + data.get("avatar").asText())
.blog("https://dev.tencent.com/" + data.get("path").asText())
.nickname(data.get("name").asText())
.company(data.get("company").asText())
.location(data.get("location").asText())
.gender(AuthUserGender.getRealGender(data.get("sex").asText()))
.email(data.get("email").asText())
.remark(data.get("slogan").asText())
.token(authToken)
.source(AuthSource.TENCENT_CLOUD)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthToutiaoErrorCode;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 今日头条登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.5
* @since 1.5
*/
public class AuthToutiaoRequest extends BaseAuthRequest {
public AuthToutiaoRequest(AuthConfig config) {
super(config, AuthSource.TOUTIAO);
}
@Override
public String authorize() {
return UrlBuilder.getToutiaoAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getToutiaoAccessTokenUrl(config.getClientId(), config.getClientSecret(), code);
JsonNode object = HttpRequest.get(accessTokenUrl)
.execute()
.asJsonNode();
if (object.has("error_code")) {
throw new AuthException(AuthToutiaoErrorCode.getErrorCode(object.get("error_code").asInt()).getDesc());
}
return AuthToken.builder()
.accessToken(object.get("access_token").asText())
.expireIn(object.get("expires_in").asInt())
.openId(object.get("open_id").asText())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
JsonNode userProfile = HttpRequest.get(UrlBuilder.getToutiaoUserInfoUrl(config.getClientId(), authToken.getAccessToken()))
.execute()
.asJsonNode();
if (userProfile.has("error_code")) {
throw new AuthException(AuthToutiaoErrorCode.getErrorCode(userProfile.get("error_code").asInt()).getDesc());
}
JsonNode user = userProfile.get("data");
boolean isAnonymousUser = user.get("uid_type").asInt() == 14;
String anonymousUserName = "匿名用户";
return AuthUser.builder()
.uuid(user.get("uid").asText())
.username(isAnonymousUser ? anonymousUserName : user.get("screen_name").asText())
.nickname(isAnonymousUser ? anonymousUserName : user.get("screen_name").asText())
.avatar(user.get("avatar_url").asText())
.remark(user.get("description").asText())
.gender(AuthUserGender.getRealGender(user.get("gender").asText()))
.token(authToken)
.source(AuthSource.TOUTIAO)
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthResponse;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 微信登录
*
* @author yangkai.shen (https://xkcoding.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthWeChatRequest extends BaseAuthRequest {
public AuthWeChatRequest(AuthConfig config) {
super(config, AuthSource.WECHAT);
}
@Override
public String authorize() {
return UrlBuilder.getWeChatAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
/**
* 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
*
* @param code 授权码
* @return 所有信息
*/
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getWeChatAccessTokenUrl(config.getClientId(), config.getClientSecret(), code);
return this.getToken(accessTokenUrl);
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
String openId = authToken.getOpenId();
JsonNode object = HttpRequest.get(UrlBuilder.getWeChatUserInfoUrl(accessToken, openId))
.execute()
.asJsonNode();
this.checkResponse(object);
return AuthUser.builder()
.username(object.get("nickname").asText())
.nickname(object.get("nickname").asText())
.avatar(object.get("headimgurl").asText())
.location(object.get("country").asText() + "-" + object.get("province").asText() + "-" + object.get("city").asText())
.uuid(openId)
.gender(AuthUserGender.getRealGender(object.get("sex").asText()))
.token(authToken)
.source(AuthSource.WECHAT)
.build();
}
@Override
public AuthResponse refresh(AuthToken oldToken) {
String refreshTokenUrl = UrlBuilder.getWeChatRefreshUrl(config.getClientId(), oldToken.getRefreshToken());
return AuthResponse.builder()
.code(ResponseStatus.SUCCESS.getCode())
.data(this.getToken(refreshTokenUrl))
.build();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
*/
private void checkResponse(JsonNode object) {
if (object.has("errcode")) {
throw new AuthException(object.get("errcode").asInt(), object.get("errmsg").asText());
}
}
/**
* 获取token,适用于获取access_token和刷新token
*
* @param accessTokenUrl 实际请求token的地址
* @return token对象
*/
private AuthToken getToken(String accessTokenUrl) {
JsonNode object = HttpRequest.get(accessTokenUrl)
.execute()
.asJsonNode();
this.checkResponse(object);
return AuthToken.builder()
.accessToken(object.get("access_token").asText())
.refreshToken(object.get("refresh_token").asText())
.expireIn(object.get("expires_in").asInt())
.openId(object.get("openid").asText())
.build();
}
}
package net.dreamlu.mica.social.request;
import com.fasterxml.jackson.databind.JsonNode;
import net.dreamlu.http.HttpRequest;
import net.dreamlu.mica.core.utils.INetUtil;
import net.dreamlu.mica.core.utils.StringUtil;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.model.AuthUserGender;
import net.dreamlu.mica.social.utils.UrlBuilder;
/**
* 微博登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
public class AuthWeiboRequest extends BaseAuthRequest {
public AuthWeiboRequest(AuthConfig config) {
super(config, AuthSource.WEIBO);
}
@Override
public String authorize() {
return UrlBuilder.getWeiboAuthorizeUrl(config.getClientId(), config.getRedirectUri());
}
@Override
protected AuthToken getAccessToken(String code) {
String accessTokenUrl = UrlBuilder.getWeiboAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
JsonNode accessTokenObject = HttpRequest.post(accessTokenUrl)
.execute()
.asJsonNode();
if (accessTokenObject.has("error")) {
throw new AuthException("Unable to get token from weibo using code [" + code + "]:" + accessTokenObject.get("error_description").asText());
}
return AuthToken.builder()
.accessToken(accessTokenObject.get("access_token").asText())
.uid(accessTokenObject.get("uid").asText())
.expireIn(accessTokenObject.get("remind_in").asInt())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
String uid = authToken.getUid();
String oauthParam = String.format("uid=%s&access_token=%s", uid, accessToken);
JsonNode jsonNode = HttpRequest.get(UrlBuilder.getWeiboUserInfoUrl(oauthParam))
.addHeader("Authorization", "OAuth2 " + oauthParam)
.addHeader("API-RemoteIP", INetUtil.getHostIp())
.execute()
.asJsonNode();
if (jsonNode.has("error")) {
throw new AuthException(jsonNode.get("error").asText());
}
return AuthUser.builder()
.uuid(jsonNode.get("id").asText())
.username(jsonNode.get("name").asText())
.avatar(jsonNode.get("profile_image_url").asText())
.blog(StringUtil.isBlank(jsonNode.get("url").asText()) ? "https://weibo.com/" + jsonNode.get("profile_url").asText() : jsonNode.get("url").asText())
.nickname(jsonNode.get("screen_name").asText())
.location(jsonNode.get("location").asText())
.remark(jsonNode.get("description").asText())
.gender(AuthUserGender.getRealGender(jsonNode.get("gender").asText()))
.token(authToken)
.source(AuthSource.WEIBO)
.build();
}
}
package net.dreamlu.mica.social.request;
import lombok.Getter;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.config.AuthSource;
import net.dreamlu.mica.social.exception.AuthException;
import net.dreamlu.mica.social.model.AuthResponse;
import net.dreamlu.mica.social.model.AuthToken;
import net.dreamlu.mica.social.model.AuthUser;
import net.dreamlu.mica.social.utils.AuthConfigChecker;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
@Getter
public abstract class BaseAuthRequest implements AuthRequest {
protected final AuthConfig config;
protected final AuthSource authSource;
public BaseAuthRequest(AuthConfig config, AuthSource authSource) {
this.config = config;
this.authSource = authSource;
if (!AuthConfigChecker.isSupportedAuth(config)) {
throw new AuthException(ResponseStatus.PARAMETER_INCOMPLETE);
}
}
protected abstract AuthToken getAccessToken(String code);
protected abstract AuthUser getUserInfo(AuthToken authToken);
@Override
public AuthResponse login(String code) {
try {
AuthToken authToken = this.getAccessToken(code);
AuthUser user = this.getUserInfo(authToken);
return AuthResponse.builder().code(ResponseStatus.SUCCESS.getCode()).data(user).build();
} catch (Exception e) {
return this.responseError(e);
}
}
private AuthResponse responseError(Exception e) {
int errorCode = ResponseStatus.FAILURE.getCode();
if (e instanceof AuthException) {
errorCode = ((AuthException) e).getErrorCode();
}
return AuthResponse.builder().code(errorCode).msg(e.getMessage()).build();
}
@Override
public abstract String authorize();
}
package net.dreamlu.mica.social.request;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com), L.cm
* @version 1.0
* @since 1.8
*/
@Getter
@AllArgsConstructor
public enum ResponseStatus {
/**
* 相应状态
*/
SUCCESS(2000, "Success"),
FAILURE(5000, "Failure"),
NOT_IMPLEMENTED(5001, "Not Implemented"),
PARAMETER_INCOMPLETE(5002, "Parameter incomplete"),
UNSUPPORTED(5003, "Unsupported operation"),
NO_AUTH_SOURCE(5004, "AuthSource cannot be null"),
UNIDENTIFIED_PLATFORM(5005, "Unidentified platform"),
;
private int code;
private String msg;
}
package net.dreamlu.mica.social.utils;
import net.dreamlu.mica.core.utils.StringUtil;
import net.dreamlu.mica.social.config.AuthConfig;
/**
* 授权配置类的校验器
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
public class AuthConfigChecker {
/**
* 是否支持第三方登录
*
* @param config config
* @return true or false
*/
public static boolean isSupportedAuth(AuthConfig config) {
return StringUtil.isNotBlank(config.getClientId())
&& StringUtil.isNotBlank(config.getClientSecret())
&& StringUtil.isNotBlank(config.getRedirectUri());
}
}
package net.dreamlu.mica.social.utils;
import lombok.experimental.UtilityClass;
import net.dreamlu.mica.core.utils.Base64Util;
import net.dreamlu.mica.core.utils.DigestUtil;
import net.dreamlu.mica.social.exception.AuthException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
/**
* 全局的工具类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@UtilityClass
public class GlobalAuthUtil {
private static final String DEFAULT_ENCODING = "UTF-8";
public static String generateDingTalkSignature(String canonicalString, String secret) {
String hmacSha256Hex = DigestUtil.hmacSha256Hex(canonicalString, secret);
return urlEncode(Base64Util.encode(hmacSha256Hex));
}
private static String urlEncode(String value) {
if (value == null) {
return "";
}
try {
String encoded = URLEncoder.encode(value, GlobalAuthUtil.DEFAULT_ENCODING);
return encoded.replace("+", "%20").replace("*", "%2A")
.replace("~", "%7E").replace("/", "%2F");
} catch (UnsupportedEncodingException e) {
throw new AuthException("Failed To Encode Uri", e);
}
}
public static String urlDecode(String value) {
if (value == null) {
return "";
}
try {
return URLDecoder.decode(value, GlobalAuthUtil.DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new AuthException("Failed To Decode Uri", e);
}
}
public static Map<String, String> parseStringToMap(String paramsStr) {
int pathEndPos = paramsStr.indexOf('?');
if (pathEndPos > -1) {
paramsStr = paramsStr.split("\\?")[1];
}
Map<String, String> res = new HashMap<>();
if (paramsStr.contains("&")) {
String[] fields = paramsStr.split("&");
for (String field : fields) {
if (field.contains("=")) {
String[] keyValue = field.split("=");
res.put(GlobalAuthUtil.urlDecode(keyValue[0]), keyValue.length == 2 ? GlobalAuthUtil.urlDecode(keyValue[1]) : null);
}
}
}
return res;
}
}
package net.dreamlu.mica.social;
import net.dreamlu.mica.social.config.AuthConfig;
import net.dreamlu.mica.social.model.AuthResponse;
import net.dreamlu.mica.social.request.*;
import org.junit.Test;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
public class AuthRequestTest {
@Test
public void giteeTest() {
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
authRequest.login("code");
}
@Test
public void githubTest() {
AuthRequest authRequest = new AuthGithubRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
authRequest.login("code");
}
@Test
public void weiboTest() {
AuthRequest authRequest = new AuthWeiboRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
authRequest.login("code");
}
@Test
public void dingdingTest() {
AuthRequest authRequest = new AuthDingTalkRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
authRequest.login("code");
}
@Test
public void baiduTest() {
AuthRequest authRequest = new AuthBaiduRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
authRequest.login("code");
}
@Test
public void codingTest() {
AuthRequest authRequest = new AuthCodingRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
authRequest.login("code");
}
@Test
public void tencentCloudTest() {
AuthRequest authRequest = new AuthTencentCloudRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
authRequest.login("code");
}
@Test
public void oschinaTest() {
AuthRequest authRequest = new AuthOschinaRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
authRequest.login("code");
}
@Test
public void qqTest() {
AuthRequest authRequest = new AuthQqRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
AuthResponse login = authRequest.login("code");
}
@Test
public void wechatTest() {
AuthRequest authRequest = new AuthWeChatRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
AuthResponse login = authRequest.login("code");
}
@Test
public void googleTest() {
AuthRequest authRequest = new AuthGoogleRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
AuthResponse login = authRequest.login("code");
}
@Test
public void facebookTest() {
AuthRequest authRequest = new AuthFacebookRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
AuthResponse login = authRequest.login("code");
}
@Test
public void microsoftTest() {
AuthRequest authRequest = new AuthMicrosoftRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
AuthResponse login = authRequest.login("code");
}
@Test
public void miTest() {
AuthRequest authRequest = new AuthMiRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// 返回授权页面,可自行调整
String authorize = authRequest.authorize();
System.out.println(authorize);
// 授权登录后会返回一个code,用这个code进行登录
AuthResponse login = authRequest.login("code");
}
}
......@@ -8,9 +8,9 @@ include "mica-boot"
include "mica-boot-test"
include "mica-captcha"
include "mica-cloud"
include "mica-social"
include "mica-plus-error-catch"
include "mica-plus-redis"
include "mica-plus-mongo"
include "mica-plus-swagger"
include "mica-plus-ribbon"
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册