一文詳解Java中的AuthRequest類(附Demo)
前言
公共接口,定義了對第三方平臺進(jìn)行授權(quán)、登錄、撤銷授權(quán)和刷新 token 的操作
1. 基本知識
先看源碼基本API接口:
import me.zhyd.oauth.enums.AuthResponseStatus; import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthToken; /** * JustAuth {@code Request}公共接口,所有平臺的{@code Request}都需要實(shí)現(xiàn)該接口 * <p> * {@link AuthRequest#authorize()} * {@link AuthRequest#authorize(String)} * {@link AuthRequest#login(AuthCallback)} * {@link AuthRequest#revoke(AuthToken)} * {@link AuthRequest#refresh(AuthToken)} * * @author yadong.zhang (yadong.zhang0415(a)gmail.com) * @since 1.8 */ public interface AuthRequest { /** * 返回授權(quán)url,可自行跳轉(zhuǎn)頁面 * <p> * 不建議使用該方式獲取授權(quán)地址,不帶{@code state}的授權(quán)地址,容易受到csrf攻擊。 * 建議使用{@link AuthDefaultRequest#authorize(String)}方法生成授權(quán)地址,在回調(diào)方法中對{@code state}進(jìn)行校驗(yàn) * * @return 返回授權(quán)地址 */ @Deprecated default String authorize() { throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED); } /** * 返回帶{@code state}參數(shù)的授權(quán)url,授權(quán)回調(diào)時會帶上這個{@code state} * * @param state state 驗(yàn)證授權(quán)流程的參數(shù),可以防止csrf * @return 返回授權(quán)地址 */ default String authorize(String state) { throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED); } /** * 第三方登錄 * * @param authCallback 用于接收回調(diào)參數(shù)的實(shí)體 * @return 返回登錄成功后的用戶信息 */ default AuthResponse login(AuthCallback authCallback) { throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED); } /** * 撤銷授權(quán) * * @param authToken 登錄成功后返回的Token信息 * @return AuthResponse */ default AuthResponse revoke(AuthToken authToken) { throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED); } /** * 刷新access token (續(xù)期) * * @param authToken 登錄成功后返回的Token信息 * @return AuthResponse */ default AuthResponse refresh(AuthToken authToken) { throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED); } }
大致方法如下:
authorize()
:返回授權(quán) URL,但已被標(biāo)記為過時 (@Deprecated)。不建議使用此方法獲取授權(quán)地址,因?yàn)椴粠?state 的授權(quán)地址容易受到 CSRF 攻擊authorize(String state)
:返回帶 state 參數(shù)的授權(quán) URL,授權(quán)回調(diào)時會帶上這個 state,用于驗(yàn)證授權(quán)流程的參數(shù),防止 CSRF 攻擊login(AuthCallback authCallback)
:第三方登錄方法,用于接收回調(diào)參數(shù)的實(shí)體,并返回登錄成功后的用戶信息revoke(AuthToken authToken)
:撤銷授權(quán)方法,用于撤銷登錄成功后返回的 Token 信息refresh(AuthToken authToken)
:刷新 Access Token 方法,用于續(xù)期登錄成功后返回的 Token 信息
2. Demo
根據(jù)上述接口,簡單測試下接口功能:
制造一個第三方的類:
package com.example.test; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthToken; import me.zhyd.oauth.request.AuthRequest; public class GitHubAuthProvider implements AuthRequest { @Override public String authorize(String state) { // 返回 GitHub 授權(quán) URL,并將 state 參數(shù)添加到 URL 中 return "https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&state=" + state; } @Override public AuthResponse login(AuthCallback authCallback) { // 模擬 GitHub 登錄成功后返回的用戶信息 return new AuthResponse(200, "Success", "GitHubUser,github@example.com"); } @Override public AuthResponse revoke(AuthToken authToken) { // 撤銷授權(quán)的具體實(shí)現(xiàn) return new AuthResponse(200, "Success", "Authorization revoked successfully"); } @Override public AuthResponse refresh(AuthToken authToken) { // 刷新 Access Token 的具體實(shí)現(xiàn) return new AuthResponse(200, "Success", "Access Token refreshed successfully"); } }
對應(yīng)的接口測試類如下:
import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthToken; import me.zhyd.oauth.request.AuthRequest; public class test { public static void main(String[] args) { // 創(chuàng)建一個第三方平臺的具體實(shí)現(xiàn)對象 AuthRequest authRequest = new GitHubAuthProvider(); // 獲取授權(quán) URL,傳入 state 參數(shù) String authorizeUrl = authRequest.authorize("random_state_parameter"); System.out.println("Authorize URL: " + authorizeUrl); // 模擬第三方登錄操作,傳入 AuthCallback 實(shí)體 AuthResponse authResponse = authRequest.login(new AuthCallback()); System.out.println("Login response: " + authResponse); // 模擬撤銷授權(quán)操作,傳入登錄成功后返回的 Token 信息 AuthToken authToken = new AuthToken(); AuthResponse revokeResponse = authRequest.revoke(authToken); System.out.println("Revoke response: " + revokeResponse); // 模擬刷新 Access Token 操作,傳入登錄成功后返回的 Token 信息 AuthResponse refreshResponse = authRequest.refresh(authToken); System.out.println("Refresh response: " + refreshResponse); } }
截圖如下:(默認(rèn)的 toString() 方法返回的對象字符串表示形式)
3. 實(shí)戰(zhàn)
上述Demo只是一個簡易版
在實(shí)戰(zhàn)中應(yīng)對各個不同的應(yīng)用,可以寫個模板類
import java.util.Objects; import me.zhyd.oauth.config.AuthConfig; import me.zhyd.oauth.config.AuthDefaultSource; import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.request.AuthAlipayRequest; import me.zhyd.oauth.request.AuthBaiduRequest; import me.zhyd.oauth.request.AuthCodingRequest; import me.zhyd.oauth.request.AuthCsdnRequest; import me.zhyd.oauth.request.AuthDingTalkRequest; import me.zhyd.oauth.request.AuthDouyinRequest; import me.zhyd.oauth.request.AuthElemeRequest; import me.zhyd.oauth.request.AuthFacebookRequest; import me.zhyd.oauth.request.AuthGiteeRequest; import me.zhyd.oauth.request.AuthGithubRequest; import me.zhyd.oauth.request.AuthGitlabRequest; import me.zhyd.oauth.request.AuthGoogleRequest; import me.zhyd.oauth.request.AuthHuaweiRequest; import me.zhyd.oauth.request.AuthKujialeRequest; import me.zhyd.oauth.request.AuthLinkedinRequest; import me.zhyd.oauth.request.AuthMeituanRequest; import me.zhyd.oauth.request.AuthMiRequest; import me.zhyd.oauth.request.AuthMicrosoftRequest; import me.zhyd.oauth.request.AuthOschinaRequest; import me.zhyd.oauth.request.AuthPinterestRequest; import me.zhyd.oauth.request.AuthQqRequest; import me.zhyd.oauth.request.AuthRenrenRequest; import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.request.AuthStackOverflowRequest; import me.zhyd.oauth.request.AuthTaobaoRequest; import me.zhyd.oauth.request.AuthTeambitionRequest; import me.zhyd.oauth.request.AuthToutiaoRequest; import me.zhyd.oauth.request.AuthTwitterRequest; import me.zhyd.oauth.request.AuthWeChatEnterpriseRequest; import me.zhyd.oauth.request.AuthWeChatMpRequest; import me.zhyd.oauth.request.AuthWeChatOpenRequest; import me.zhyd.oauth.request.AuthWeiboRequest; import org.springblade.core.social.props.SocialProperties; public class SocialUtil { public SocialUtil() { } public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) { AuthDefaultSource authSource = (AuthDefaultSource)Objects.requireNonNull(AuthDefaultSource.valueOf(source.toUpperCase())); AuthConfig authConfig = (AuthConfig)socialProperties.getOauth().get(authSource); if (authConfig == null) { throw new AuthException("未獲取到有效的Auth配置"); } else { AuthRequest authRequest = null; switch (authSource) { case GITHUB: authRequest = new AuthGithubRequest(authConfig); break; case GITEE: authRequest = new AuthGiteeRequest(authConfig); break; case OSCHINA: authRequest = new AuthOschinaRequest(authConfig); break; case QQ: authRequest = new AuthQqRequest(authConfig); break; case WECHAT_OPEN: authRequest = new AuthWeChatOpenRequest(authConfig); break; case WECHAT_ENTERPRISE: authRequest = new AuthWeChatEnterpriseRequest(authConfig); break; case WECHAT_MP: authRequest = new AuthWeChatMpRequest(authConfig); break; case DINGTALK: authRequest = new AuthDingTalkRequest(authConfig); break; case ALIPAY: authRequest = new AuthAlipayRequest(authConfig); break; case BAIDU: authRequest = new AuthBaiduRequest(authConfig); break; case WEIBO: authRequest = new AuthWeiboRequest(authConfig); break; case CODING: authRequest = new AuthCodingRequest(authConfig); break; case CSDN: authRequest = new AuthCsdnRequest(authConfig); break; case TAOBAO: authRequest = new AuthTaobaoRequest(authConfig); break; case GOOGLE: authRequest = new AuthGoogleRequest(authConfig); break; case FACEBOOK: authRequest = new AuthFacebookRequest(authConfig); break; case DOUYIN: authRequest = new AuthDouyinRequest(authConfig); break; case LINKEDIN: authRequest = new AuthLinkedinRequest(authConfig); break; case MICROSOFT: authRequest = new AuthMicrosoftRequest(authConfig); break; case MI: authRequest = new AuthMiRequest(authConfig); break; case TOUTIAO: authRequest = new AuthToutiaoRequest(authConfig); break; case TEAMBITION: authRequest = new AuthTeambitionRequest(authConfig); break; case PINTEREST: authRequest = new AuthPinterestRequest(authConfig); break; case RENREN: authRequest = new AuthRenrenRequest(authConfig); break; case STACK_OVERFLOW: authRequest = new AuthStackOverflowRequest(authConfig); break; case HUAWEI: authRequest = new AuthHuaweiRequest(authConfig); break; case KUJIALE: authRequest = new AuthKujialeRequest(authConfig); break; case GITLAB: authRequest = new AuthGitlabRequest(authConfig); break; case MEITUAN: authRequest = new AuthMeituanRequest(authConfig); break; case ELEME: authRequest = new AuthElemeRequest(authConfig); break; case TWITTER: authRequest = new AuthTwitterRequest(authConfig); } if (null == authRequest) { throw new AuthException("未獲取到有效的Auth配置"); } else { return (AuthRequest)authRequest; } } } }
類似的Github第三方平臺如下:(以下類為API自帶的)
import com.alibaba.fastjson.JSONObject; import me.zhyd.oauth.cache.AuthStateCache; import me.zhyd.oauth.config.AuthConfig; import me.zhyd.oauth.config.AuthDefaultSource; import me.zhyd.oauth.enums.AuthUserGender; import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthToken; import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.utils.GlobalAuthUtils; import java.util.Map; /** * Github登錄 * * @author yadong.zhang (yadong.zhang0415(a)gmail.com) * @since 1.0.0 */ public class AuthGithubRequest extends AuthDefaultRequest { public AuthGithubRequest(AuthConfig config) { super(config, AuthDefaultSource.GITHUB); } public AuthGithubRequest(AuthConfig config, AuthStateCache authStateCache) { super(config, AuthDefaultSource.GITHUB, authStateCache); } @Override protected AuthToken getAccessToken(AuthCallback authCallback) { String response = doPostAuthorizationCode(authCallback.getCode()); Map<String, String> res = GlobalAuthUtils.parseStringToMap(response); this.checkResponse(res.containsKey("error"), res.get("error_description")); return AuthToken.builder() .accessToken(res.get("access_token")) .scope(res.get("scope")) .tokenType(res.get("token_type")) .build(); } @Override protected AuthUser getUserInfo(AuthToken authToken) { String response = doGetUserInfo(authToken); JSONObject object = JSONObject.parseObject(response); this.checkResponse(object.containsKey("error"), object.getString("error_description")); return AuthUser.builder() .rawUserInfo(object) .uuid(object.getString("id")) .username(object.getString("login")) .avatar(object.getString("avatar_url")) .blog(object.getString("blog")) .nickname(object.getString("name")) .company(object.getString("company")) .location(object.getString("location")) .email(object.getString("email")) .remark(object.getString("bio")) .gender(AuthUserGender.UNKNOWN) .token(authToken) .source(source.toString()) .build(); } private void checkResponse(boolean error, String error_description) { if (error) { throw new AuthException(error_description); } } }
后續(xù)在使用過程的代碼如下:
@NonDS @Slf4j @RestController @AllArgsConstructor @ConditionalOnProperty(value = "social.enabled", havingValue = "true") public class BladeSocialEndpoint { private final SocialProperties socialProperties; /** * 授權(quán)完畢跳轉(zhuǎn) */ @RequestMapping("/oauth/render/{source}") public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException { AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties); String authorizeUrl = authRequest.authorize(AuthStateUtils.createState()); response.sendRedirect(authorizeUrl); } /** * 獲取認(rèn)證信息 */ @RequestMapping("/oauth/callback/{source}") public Object login(@PathVariable("source") String source, AuthCallback callback) { AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties); return authRequest.login(callback); } /** * 撤銷授權(quán) */ @RequestMapping("/oauth/revoke/{source}/{token}") public Object revokeAuth(@PathVariable("source") String source, @PathVariable("token") String token) { AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties); return authRequest.revoke(AuthToken.builder().accessToken(token).build()); } /** * 續(xù)期令牌 */ @RequestMapping("/oauth/refresh/{source}") public Object refreshAuth(@PathVariable("source") String source, String token) { AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties); return authRequest.refresh(AuthToken.builder().refreshToken(token).build()); } }
以上就是一文詳解Java中的AuthRequest類(附Demo)的詳細(xì)內(nèi)容,更多關(guān)于Java AuthRequest類的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java運(yùn)行時數(shù)據(jù)區(qū)域和類結(jié)構(gòu)詳解
這篇文章主要介紹了java運(yùn)行時數(shù)據(jù)區(qū)域和類結(jié)構(gòu),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07Java?Kryo,Protostuff,Hessian序列化方式對比
這篇文章主要介紹了Java?Kryo,Protostuff,Hessian序列化方式對比,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07Java使用POI導(dǎo)出Excel(一):單sheet
這篇文章介紹了Java使用POI導(dǎo)出Excel的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10使用Spring事件監(jiān)聽機(jī)制實(shí)現(xiàn)跨模塊調(diào)用的步驟詳解
Spring 事件監(jiān)聽機(jī)制是 Spring 框架中用于在應(yīng)用程序的不同組件之間進(jìn)行通信的一種機(jī)制,Spring 事件監(jiān)聽機(jī)制基于觀察者設(shè)計(jì)模式,使得應(yīng)用程序的各個部分可以解耦,提高模塊化和可維護(hù)性,本文給大家介紹了使用Spring事件監(jiān)聽機(jī)制實(shí)現(xiàn)跨模塊調(diào)用,需要的朋友可以參考下2024-06-06