项目中接入QQ登录
接上篇介绍申请APPID和APPKEY的文章,本篇文章介绍如何将QQ登录接入自己的项目。(申请成功后,将你自己APPID和回调地址填上,点击QQ登录正常要能弹出登陆页面)
QQ登录的流程
- 点击qq登录,弹出登陆页面,授权登录。
- 页面会自动重定向到你填写的回调地址并拼接一个code参数。
- 通过使用code,向qq接口请求获取用户信息并返回前端。
分析
最开始我以为是在自己后端中实现回调地址接口,因为QQ是根据回调地址将code值传给我们,但想了一下,这样虽然没问题,后端能拿到code,并向qq发送请求获取用户信息,但获取到的用户信息好像返回不了给前端,因为这个回调请求不是前端发起的。后来看视频才知道,回调地址是前端的一个地址。前端页面通过获取地址栏的code后,再将code向发送给后端,后端拿到code获取到用户信息后就能返回给前端了。
综上,前端得有一个对应回调地址的页面,通过 location.search 获取到地址栏的code值,最后,在向后端接口发请求,将code值传递过去,后端接口进行相应的操作。这里的回调地址页面不需要任何内容,就是一个空页面。
不过有一点注意,回调地址由于是域名,但我们在本地测试,启动的项目访问地址都是localhost,所以可以在本地的hosts文件里面添加一个域名解析,将你的域名解析成127.0.0.1,并且启动前端的时候,将前端项目设置为80端口。
##本地host文件 C:\Windows\System32\drivers\etc 下的hosts文件
## 在文件最后加上 127.0.0.1 域名
## 改hosts文件直接先在其他位置创建一个hosts.txt 把hosts文件中的内容拷贝到hosts.txt文件中,并在最后添加域名解析,最后改为hosts,直接替换etc下的,直接修改hosts有权限问题
前端可能重定向后出现 invalid host header 问题(没有就忽略),好像是前端禁止域名访问导致的,在前端配置文件vue.config.js的devServer中添加以下代码
allowedHosts: [
'xxxx.com', // 允许访问的域名地址,即花生壳内网穿透的地址
'.xxxx.com' // .是二级域名的通配符
],
代码
前端对应的回调地址页面代码
<template>
<div>
登录中...
</div>
</template>
<script>
import request from '../utils/request'
export default {
name: "login",
created() {
let param=location.search //param的值为 ?code=value
let code=param.split("=")[1] //code的值为 value
console.log(code)
this.login(code)
},
methods: {
login(code) {
request.get("/qqlogin?code="+code).then(res => { //这里的接口和你自己后端实现的一致
console.log(res.data); //这里就可以根据你自己的前端逻辑来操作数据或者跳转页面了
})
}
}
};
</script>
前端路由中记得配上
// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//引入组件
import Home from '../components/Home'
import Login from '../components/Login'
//创建并暴露一个路由器
export default new VueRouter({
mode: 'history',
routes:[
{
path:'/home',
component:Home
},
{
path:'/login',
component:Login
}
]
})
后端接口 /qqlogin 的代码
@GetMapping("/qqlogin")
public User callback(String code, HttpServletResponse response) throws IOException {
String accessToken = QQLoginUtil.getAccessToken(code);
String openId = QQLoginUtil.getOpenId(accessToken);
return QQLoginUtil.getUserInfo(accessToken, openId);
}
QQLoginUtil就是把那些调用qq接口的操作封装了一下,代码如下。代码中的接口和参数以及返回值都是官网有说明的,感兴趣的可以官网看看。
public class QQLoginUtil {
private static String appid = ""; //你自己的
private static String appkey = "";
private static String redirect_url = "";
private static RestTemplate restTemplate = new RestTemplate(); //可以用其他的http客户端工具
/**
* 根据code拿到access_token
* @param code
* @return
*/
public static String getAccessToken(String code) {
String access_token_url = "https://graph.qq.com/oauth2.0/token?fmt=json&" + "grant_type=authorization_code" + "&client_id=" + appid + "&client_secret=" + appkey + "&redirect_uri=" + redirect_url + "&code=" + code;
String json = restTemplate.getForObject(access_token_url, String.class);
JSONObject result = JSONUtil.parseObj(json);
String access_token = (String) result.get("access_token");
return access_token;
}
/**
* 根据access_token拿到openid 这个openid其实就是用户唯一的身份,可以存数据库作为用户唯一标识
* @param access_token
* @return
*/
public static String getOpenId(String access_token) {
String openid_url = "https://graph.qq.com/oauth2.0/me?fmt=json&access_token=" + access_token;
String json = restTemplate.getForObject(openid_url, String.class);
JSONObject entries = JSONUtil.parseObj(json);
String openid = (String) entries.get("openid");
return openid;
}
/**
* 根据openid 拿到用户的基本信息,包括头像,昵称等
* @param access_token
* @param openid
* @return
*/
public static User getUserInfo(String access_token, String openid) {
String get_userinfo_url = "https://graph.qq.com/user/get_user_info?fmt=json&access_token=" + access_token + "&oauth_consumer_key=" + appid + "&openid=" + openid;
String json = restTemplate.getForObject(get_userinfo_url, String.class);
System.out.println(json);
JSONObject result = JSONUtil.parseObj(json);
User user = new User();
user.setName((String) result.get("nickname")).setSex((String) result.get("gender")).setImage((String) result.get("figureurl_qq"));
return user;
}
}