java sdk qq登录授权,springboot开发qq第三方授权登录(示例代码)

前几天随手写了一个qq第三方授权登录功能,现总结一下(这里以个人开发网站应用为例):

20200225122711757324.png

然后开始创应用,我这边是网站应用,创建流程请参考文档https://wiki.connect.qq.com/__trashed-2和百度,创建过程中请注意网站域名回调和备案号要和备案信息一致!资料填写完最多7个工作日就可以审核完成,完成之后为(示例):

20200225122711984848.png

点击查看主要是要拿到应用的APPID和APPKEY(示例):

20200225122712211396.png

基本信息都拿到之后请仔细阅读开发文档查看需要用到的sdk及api开始进行开发。我这边的后端架构用的是springboot2.2.x+mybatis annotation 前端用的是layui,不过基本逻辑都一样:

首先将一些固定数据 APPID(网站应用审核通过后获取的APPID),APPKEY(网站应用审核通过后获取的APPKEY),DOMAIN(申请的域名),CALLBACK(回调地址)写到配置文件或者静态资源类中去,方便修改和调用(在网站应用中的网站回调域可以加一个测试的地址,例如:http://127.0.0.1:8080/callback[callback是示例,具体回调地址以自己为准])。

示例:

1 public classQQWikiParamter {2

3 public static final String APPID = "";4

5 public static final String APPKEY = "";6

7 //public static final String DOMAIN = "http://127.0.0.1:8080";

8

9 public static final String DOMAIN = "";10

11 public static final String REDIRECT_URL = "";12 }

通过查看文档得知我们需要用到一些api,由此封装一个工具类commonUtil:

jia.gif

jian.gif

1 importnet.sf.json.JSONException;2 importnet.sf.json.JSONObject;3 importorg.apache.commons.lang3.StringUtils;4 importorg.slf4j.Logger;5 importorg.slf4j.LoggerFactory;6

7 importjavax.net.ssl.HttpsURLConnection;8 importjavax.net.ssl.SSLContext;9 importjavax.net.ssl.SSLSocketFactory;10 importjavax.net.ssl.TrustManager;11 importjava.io.BufferedReader;12 importjava.io.InputStream;13 importjava.io.InputStreamReader;14 importjava.io.OutputStream;15 importjava.net.ConnectException;16 importjava.net.URL;17

18 /**

19 *@authorkabuqinuo20 * @date 2020/2/18 12:5021 */

22 public classCommonUtil {23

24 private static Logger log = LoggerFactory.getLogger(CommonUtil.class);25

26 //获取Authorization Code

27 public final static String auth_url = "https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=APPID&redirect_uri=REDIRECTURL&&state=STATE";28 //凭证获取(GET)

29 public final static String token_url = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=APPID&client_secret=APPSECRET&code=CODE&redirect_uri=REDIRECTURL";30 //权限自动续期,获取Access Token

31 public final static String refresh_token_url = "https://graph.qq.com/oauth2.0/token?grant_type=refresh_token&client_id=APPID&client_secret=APPSECRET&refresh_token=REFRESHTOKEN";32 //获取用户OpenID_OAuth2.0

33 public final static String oauth_url = "https://graph.qq.com/oauth2.0/me?access_token=ACCESSTOKEN";34 //获取登录用户的昵称、头像、性别

35 public final static String user_info_url = "https://graph.qq.com/user/get_user_info?access_token=ACCESSTOKEN&oauth_consumer_key=APPID&openid=OPENID";36

37

38 /**

39 * 发送https请求40 *41 *@paramrequestUrl 请求地址42 *@paramrequestMethod 请求方式(GET、POST)43 *@paramoutputStr 提交的数据44 *@returnJSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)45 */

46 public staticString httpsRequest(String requestUrl, String requestMethod, String outputStr) {47 String result = null;48 try{49 //创建SSLContext对象,并使用我们指定的信任管理器初始化

50 TrustManager[] tm = { newMyX509TrustManager() };51 SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");52 sslContext.init(null, tm, newjava.security.SecureRandom());53 //从上述SSLContext对象中得到SSLSocketFactory对象

54 SSLSocketFactory ssf =sslContext.getSocketFactory();55

56 URL url = newURL(requestUrl);57 HttpsURLConnection conn =(HttpsURLConnection) url.openConnection();58 conn.setSSLSocketFactory(ssf);59

60 conn.setDoOutput(true);61 conn.setDoInput(true);62 conn.setUseCaches(false);63 //设置请求方式(GET/POST)

64 conn.setRequestMethod(requestMethod);65

66 //当outputStr不为null时向输出流写数据

67 if (null !=outputStr) {68 OutputStream outputStream =conn.getOutputStream();69 //注意编码格式

70 outputStream.write(outputStr.getBytes("UTF-8"));71 outputStream.close();72 }73

74 //从输入流读取返回内容

75 InputStream inputStream =conn.getInputStream();76 InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");77 BufferedReader bufferedReader = newBufferedReader(inputStreamReader);78 String str = null;79 StringBuffer buffer = newStringBuffer();80 while ((str = bufferedReader.readLine()) != null) {81 buffer.append(str);82 }83

84 //释放资源

85 bufferedReader.close();86 inputStreamReader.close();87 inputStream.close();88 conn.disconnect();89 result =buffer.toString();90 } catch(ConnectException ce) {91 log.error("连接超时:{}", ce);92 } catch(Exception e) {93 log.error("https请求异常:{}", e);94 }95 returnresult;96 }97

98 /**

99 * 获取Authorization Code100 *@paramappid101 *@paramredirect_url102 *@paramstate103 *@return

104 */

105 public staticString getCode(String appid, String redirect_url, String state){106 String resUrl = auth_url.replace("APPID",appid).replace("REDIRECTURL",redirect_url).replace("STATE",state);107 returnresUrl;108 }109

110 /**

111 * 获取接口访问凭证112 *@paramappid113 *@paramappsecret114 *@paramcode115 *@paramredirect_url116 *@return

117 */

118 public staticToken getToken(String appid, String appsecret, String code, String redirect_url) {119 Token token = null;120 String requestUrl = token_url.replace("APPID", appid).replace("APPSECRET", appsecret).replace("CODE",code).replace("REDIRECTURL",redirect_url);121 //发起GET请求获取凭证

122 String content = httpsRequest(requestUrl, "GET", null);123 if(StringUtils.isNotBlank(content)){124 content = content.replace("=","":"");125 content = content.replace("&","","");126 content = "{"" + content +""}";127 JSONObject jsonObject =JSONObject.fromObject(content);128

129 if (null !=jsonObject) {130 try{131 token = newToken();132 token.setAccessToken(jsonObject.getString("access_token"));133 token.setExpiresIn(jsonObject.getInt("expires_in"));134 token.setRefreshToken(jsonObject.getString("refresh_token"));135 } catch(JSONException e) {136 token = null;137 //获取token失败

138 log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("code"), jsonObject.getString("msg"));139 }140 }141 }142 returntoken;143 }144

145 /**

146 * 权限自动续期,获取Access Token147 *@paramappid148 *@paramappsecret149 *@paramrefresh_token150 *@return

151 */

152 public staticToken getRefreshToken(String appid, String appsecret,String refresh_token) {153 Token token = null;154 String requestUrl = refresh_token_url.replace("APPID", appid).replace("APPSECRET", appsecret).replace("REFRESHTOKEN",refresh_token);155 //发起GET请求获取凭证

156 String content = httpsRequest(requestUrl, "GET", null);157 if(StringUtils.isNotBlank(content)){158 content = content.replace("=","":"");159 content = content.replace("&","","");160 content = "{"" + content +""}";161 JSONObject jsonObject =JSONObject.fromObject(content);162

163 if (null !=jsonObject) {164 try{165 token = newToken();166 token.setAccessToken(jsonObject.getString("access_token"));167 token.setExpiresIn(jsonObject.getInt("expires_in"));168 token.setRefreshToken(jsonObject.getString("refresh_token"));169 } catch(JSONException e) {170 token = null;171 //获取token失败

172 log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("code"), jsonObject.getString("msg"));173 }174 }175 }176 returntoken;177 }178

179 /**

180 * 获取用户OpenID_OAuth2.0181 *@paramaccess_token182 *@return

183 */

184 public staticMe getMe(String access_token){185 Me me = null;186 String requestUrl = oauth_url.replace("ACCESSTOKEN",access_token);187

188 //发起GET请求获取凭证

189 String result = httpsRequest(requestUrl, "GET", null);190 if(StringUtils.isNotBlank(result)) {191 try{192 me = newMe();193 me.setOpenId(StringUtils.substringBetween(result, ""openid":"", ""}"));194 } catch(JSONException e){195 me = null;196 log.error("获取用户信息失败 ");197 }198 }199 returnme;200 }201

202 /**

203 * 获取登录用户的昵称、头像、性别204 *@paramaccess_token205 *@paramappid206 *@paramopenid207 *@return

208 */

209 public staticString getUserInfo(String access_token, String appid, String openid){210 String result = null;211 String requestUrl = user_info_url.replace("ACCESSTOKEN",access_token).replace("APPID",appid).replace("OPENID",openid);212

213 //发起GET请求获取凭证

214 result= httpsRequest(requestUrl, "GET", null);215 if(StringUtils.isNotBlank(result)) {216 returnresult;217 }218 returnresult;219 }220 }

View Code

工具类涉及到的实体类示例代码:

jia.gif

jian.gif

1 @Data2 public class Token implementsSerializable {3

4 privateString accessToken;5

6 privateInteger expiresIn;7

8 privateString refreshToken;9 }

View Code

jia.gif

jian.gif

1 @Data2 public class Me implementsSerializable {3

4 privateString openId;5 }

View Code

还有一个问题是qq互联登录可能会涉及到跨域,请注意跨域配置,示例后端springboot配置跨域:

jia.gif

jian.gif

1 @Configuration2 public classCorsConfig {3

4 privateCorsConfiguration buildConfig() {5 CorsConfiguration corsConfiguration = newCorsConfiguration();6 corsConfiguration.addAllowedOrigin("*"); //1允许任何域名使用

7 corsConfiguration.addAllowedHeader("*"); //2允许任何头

8 corsConfiguration.addAllowedMethod("*"); //3允许任何方法(post、get等)

9 returncorsConfiguration;10 }11

12 @Bean13 publicCorsFilter corsFilter() {14 UrlBasedCorsConfigurationSource source = newUrlBasedCorsConfigurationSource();15 source.registerCorsConfiguration("/**", buildConfig()); //4

16 return newCorsFilter(source);17 }18 }

View Code

准备工作做完现在开始进行开发:

首先是前端:

前端页面上需要访问一个qq第三方登录的入口按钮,当然按钮就是一个qq图标,这里qq唤起授权页面有两种类型,一种是官网上的点击qq登录图标访问链接在新窗口打开授权页面;一种是点击qq登录图标在本窗口跳转授权页面;

我用的是官网上的这一种方式,在说以前简单的讲一下本窗口打开授权页面逻辑:

本窗口打开授权页面可以直接在图标所在的标签上跳转api接口访问后端,后端重定向到qq授权页面(示例):

1

我这个a标签在页面上就是qq图标的代码,a标签直接访问后端接口:

1 @GetMapping(value = "/wiki")2 @IgnoreSecurity3 public voidtoLogin(HttpServletRequest request, HttpServletResponse response) {4 String state=ToolsBarUtil.getRandomString(10);5 //重定向

6 String url = CommonUtil.getCode(QQWikiParamter.APPID, QQWikiParamter.DOMAIN +QQWikiParamter.REDIRECT_URL, state);7 try{8 response.sendRedirect(url);9 } catch(IOException e) {10 e.printStackTrace();11 }12 }

此时就点击就可以打开qq授权页面了(示例):

20200225122712506299.png

第二种也就是我现在用的这种点击qq登录在新窗口打开一个授权页面:

写一个点击事件,在点击触发事件里面打开授权页面,示例:

1 varchildWindow;2 $(".loginBody .wiki-qq").on("click",function(){3 childWindow = window.open("/info/wiki","TencentLogin",4 "width=550,height=320,menubar=1,scrollbars=1, resizable=1,status=1,titlebar=0,toolbar=0,location=1");5 })

代码示例:

jia.gif

jian.gif

1 @GetMapping(value = "/callback")2 @IgnoreSecurity3 public ModelAndView wiki(ModelAndView mvc, HttpServletRequest request, HttpServletResponse response) throwsIOException {4 String code = request.getParameter("code");5 String state = request.getParameter("state");6 if (state == null || code == null) {7 mvc.addObject("msg","授权失败");8 mvc.setViewName("login");9 returnmvc;10 }11 //获取access_token

12 Token token = CommonUtil.getToken(QQWikiParamter.APPID, QQWikiParamter.APPKEY, code, QQWikiParamter.DOMAIN +QQWikiParamter.REDIRECT_URL);13 if(StringUtils.isNotBlank(token.getAccessToken())){14 //获取用户openid

15 Me me =CommonUtil.getMe(token.getAccessToken());16 if(StringUtils.isNotBlank(me.getOpenId())){17 //获取用户信息

18 String user_info =CommonUtil.getUserInfo(token.getAccessToken(), QQWikiParamter.APPID, me.getOpenId());19

20 //获取到用户信息之后自己的处理逻辑.....

21

22 String url = "/info/login?"+ URLEncoder.encode(Base64.getBase64("openId"),"UTF-8")+"="+URLEncoder.encode(Base64.getBase64(me.getOpenId()),"UTF-8")+"&dis="+URLEncoder.encode(Base64.getBase64(ToolsBarUtil.getRandomString(10)),"UTF-8");23 mvc.addObject("url",url);24 }25 }26 mvc.setViewName("qqCallBack");27 returnmvc;28 }

View Code

这里说明一下:

如果是本窗口打开的授权页面,这里获取到用户信息之后处理完自己的逻辑可以直接跳转到首页去。因为我这边是在新窗口打开的授权页面,所以需要一个中间页面处理回调。

然后是qqCallBack页面处理(提示:我在callback接口中把获取到的openId通过加密放到了url中并带到的回调页面。)示例代码:

1

2

3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值