概述
本次整合的多个第三方登录平台都是基于oauth2.0协议的平台,使用的前提是有OAuth2.0协议有所了解,推荐阅读:阮一峰的OAuth 2.0 的一个简单解释。本次主要使用的开源组件是JustAuth
springboot后端
POM文件
<dependency>
<groupId>com.xkcoding.justauth</groupId>
<artifactId>justauth-spring-boot-starter</artifactId>
<version>${justauth-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.2.2</version>
<scope>provided</scope>
</dependency>
application 配置
justauth:
type:
QQ:
client-id: 11111111111111111
client-secret: 2a64d0f6011111111111111111
redirect-uri: http://roroschach.club/oauth2/callback/qq
ignoreCheckRedirectUri: true
GITEE:
client-id: 66ac9fd4ddafd0dbe8311111111111111111
client-secret: 9ed19d2fc9a3c7611111111111111111
redirect-uri: http://127.0.0.1:8888/oauth2/callback/gitee
OSCHINA:
client-id: NH11111111111111111
client-secret: C8dtfJSyGys11111111111111111
redirect-uri: http://127.0.0.1:8888/oauth2/callback/oschina
controller
@RequestMapping("oauth2")
@Api(tags = "oauth2", value = "Oauth2Controller")
@RestController
@Slf4j
public class Oauth2Controller {
@Autowired
AuthRequestFactory factory;
/**
* 获取第三方登录平台信息
*
* @param platform 第三方登录平台
* @return cn.com.zsw.gblog.vo.R
* @author shiwangzhou
* @date 2021-06-09 16:52
**/
@GetMapping("{platform}/info")
public R getLoginInfo(@PathVariable String platform) {
AuthRequest authRequest = factory.get(platform);
String authorize = authRequest.authorize(AuthStateUtils.createState());
log.info(authorize);
return R.SUCCESS.data(authorize);
}
@RequestMapping("/callback/{source}")
@Transactional
public R login(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request) throws Exception {
log.info("进入callback:" + source + " callback params:" + JSONObject.toJSONString(callback));
AuthRequest authRequest = factory.get(source);
AuthResponse<AuthUser> response = authRequest.login(callback);
log.info(JSONObject.toJSONString(response));
if (response.ok()) {
final UserInfoVO userInfoVO = oauthService.oauthCallback(response.getData());
return R.SUCCESS.data(userInfoVO);
}
return R.status(500).msg("登录失败");
}
}
前端
新建 oauthCallback.vue
<template>
</template>
<script>
export default {
name: "oauthCallback",
data() {
return {
authCallback: {
platform: "",
code: "",
state: "",
},
};
},
created() {
this.authCallback.platform = this.$route.params.platform;
},
mounted() {
var code = this.$utils.getUrlKey("code");
var state = this.$utils.getUrlKey("state");
this.authCallback.code = code;
this.authCallback.state = state;
//server-side模式
if (code && typeof code != "undefined") {
console.log("server-side模式:" + code);
//获取到token就是已经登录了
var token = this.$store.getters.token;
if (token && typeof token != "undefined") {
this.$router.push("/");
}
//未登录则执行登录
else {
this.$store
.dispatch("user/authCodelogin", this.authCallback)
.then(() => {
location.reload();
});
}
}
},
};
</script>
<style>
</style>
添加路由
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '@/store'
Vue.use(VueRouter)
const routes = [
{
path: '/oauth2/callback/:platform',
name: 'qqCallback',
component: () => import('../views/oauth/oauthCallback.vue'),
meta: { title: 'Gitee登录成功后回调'}
}
]
const router = new VueRouter({
// mode: 'hash', //hash模式的工作原理是hashchange事件,可以在window监听hash的变化。
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
let title = 'Gblog'
if (to.meta.params){
title = `${to.meta.title}:${to.params[to.meta.params] || ''} - ${title}`
}else {
title = `${to.meta.title} - ${title}`
}
document.title = title
store.dispatch('app/setLoading', true);
next();
})
router.afterEach((to, from) => {
// 最多延迟 关闭 loading
setTimeout(() => {
store.dispatch('app/setLoading', false);
}, 1500)
})
export default router
登录逻辑
import { login, logout, qqLogin, oauth2LoginCallback, getUserInfo } from '@/api/index'
import { getToken, setToken, removeToken, getAvatar, setAvatar, getName, setName, removeName, removeAvatar,getPermission,setPermission,removePermission } from '@/utils/auth'
const getDefaultState = () => {
return {
token: getToken(),
name: getName(),
avatar: getAvatar(),
permission: getPermission()
}
}
const state = getDefaultState()
const mutations = {
RESET_STATE: (state) => {
Object.assign(state, getDefaultState())
},
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_PERMISSION: (state, permission) => {
state.permission = permission
}
}
const actions = {
//QQ互联的server-side模式,
authCodelogin({ commit }, authcallback) {
console.log("qqCodelogin----code:" + authcallback.code);
return new Promise((resolve, reject) => {
oauth2LoginCallback(authcallback.platform,authcallback).then(res => {
let data = res.data
console.log("server-side模式, data==" + JSON.stringify(data));
console.log("server-side模式, data==" + data.token);
commit('SET_TOKEN', data.token)
commit('SET_NAME', data.nickname)
commit('SET_AVATAR', data.avatar)
commit('SET_PERMISSION', data.permission)
setPermission(data.permission)
setToken(data.token)
setAvatar(data.avatar)
setName(data.nickname)
resolve()
}).catch(error => {
reject(error)
})
})
},
}
export default {
namespaced: true,
state,
mutations,
actions
}
对接后端接口
import request from '@/utils/request'
//获取Oauth登录接口信息
export function getOauthLoginInfo(platgorm) {
return request({
url: '/oauth2/'+platgorm+'/info',
method: 'get'
})
}
//获取Oauth登录接口信息
export function oauth2LoginCallback(platgorm,data) {
return request({
url: '/oauth2/callback/'+platgorm,
method: 'post',
params:data
})
}
// 请求用户信息
export function getUserInfo() {
return request({
url: '/user/info',
method: 'get'
})
}
后记
全部代码在
https://gitee.com/gitee_zsw/Gblog
https://gitee.com/gitee_zsw/springboot-blog