springboot+mybatis+Oauth2 +vue 框架实现登录认证
1.最近在研究前后端分离项目,领导安排任务:使用Oauth2实现登录认证。因为第一次接触vue对里面的结构方法使用情况等不是很了解走了很多弯路。现在记录使用Oauth2实现登录认证,供大家参考.2.首先了解了下Oauth2认证方式。Oauth2分为四种认证方式:授权码认证(authorization-code),隐藏式(implicit),密码式(password),凭证式(client cred
·
1.最近在研究前后端分离项目,领导安排任务:使用Oauth2实现登录认证。因为第一次接触vue对里面的结构方法使用情况等不是很了解走了很多弯路。现在记录使用Oauth2实现登录认证,供大家参考.
2.首先了解了下Oauth2认证方式。
Oauth2分为四种认证方式:授权码认证(authorization-code),隐藏式(implicit),密码式(password),凭证式(client credentials)。因为是前后端分离项目,所以使用最常用的方式,安全性能高的授权码方式。
关于Oauth认证此处不做介绍。可访问链家了解详情。
此链接是妧一峰老师的文章,讲的很详细,很受用。
http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html#support
3.下面正式记录vue+springboot+oauth的登录认证实现代码。因为自己经常去网上搜索时代码都是片段,对于新手来说还是很伤脑筋,所以此处直接贴整个代码。
login.vue界面:
<template>
<div class="login">
<a-form @submit.prevent="doLogin" :autoFormCreate="(form) => this.form = form">
<a-tabs size="large" :tabBarStyle="{textAlign: 'center'}" style="padding: 0 2px;" :activeKey="activeKey"
@change="handleTabsChange">
<a-tab-pane tab="账户密码登录" key="1">
<a-alert type="error" :closable="true" v-show="error" :message="error" showIcon
style="margin-bottom: 24px;"></a-alert>
<a-form-item
fieldDecoratorId="name"
:fieldDecoratorOptions="{rules: [{ required: true, message: '请输入账户名', whitespace: true}]}">
<a-input size="large">
<a-icon slot="prefix" type="user"></a-icon>
</a-input>
</a-form-item>
<a-form-item
fieldDecoratorId="password"
:fieldDecoratorOptions="{rules: [{ required: true, message: '请输入密码', whitespace: true}]}">
<a-input size="large" type="password">
<a-icon slot="prefix" type="lock"></a-icon>
</a-input>
</a-form-item>
</a-tab-pane>
</a-tabs>
<a-form-item>
<a-button :loading="loading" style="width: 100%; margin-top: 4px" size="large" htmlType="submit" type="primary">
登录
</a-button>
</a-form-item>
<div>
<a style="float: left" @click="authentication">oauth2认证登录</a>
<a style="float: right" @click="regist">注册账户</a>
</div>
</a-form>
</div>
</template>
<script>
import {mapMutations} from 'vuex'
import Qs from 'qs'
export default {
name: 'Login',
data () {
return {
loading: false,
error: '',
activeKey: '1',
code: '',
userAuthorizationUri: 'http://10.12.0.12:8080/oauth2/authorize', // 请求授权地址
redirect_uri: 'http://localhost:8081/rapidoAdmin', // 回调地址
client_id: '75cbff63-920e-448f-bd67-8b185d907b59', // 客户端相关标识,请从认证服务器申请
client_secret: '119912f9-c015-49ae-a438-81e3edfc4de3',
loginStyle: 'popup',
state: 'rapido', // 可选参数,客户端的当前状态,可以指定任意值,用于校验,此次案例不做相关认证
response_type: 'code', // 一些固定的请求参数
grant_type: 'authorization_code'
}
},
computed: {
systemName () {
return this.$store.state.setting.systemName
},
copyright () {
return this.$store.state.setting.copyright
}
},
created () {
this.$db.clear()
this.$router.options.routes = []
},
methods: {
doLogin () {
if (this.activeKey === '1') {
// 用户名密码登录
this.form.validateFields(['name', 'password'], (errors, values) => {
if (!errors) {
this.loading = true
let name = this.form.getFieldValue('name')
let password = this.form.getFieldValue('password')
this.$post('login', {
username: name,
password: password
}).then((r) => {
let data = r.data.data
this.saveLoginData(data)
setTimeout(() => {
this.loading = false
}, 500)
this.$router.push('/')
}).catch(() => {
setTimeout(() => {
this.loading = false
}, 500)
})
}
})
}
if (this.activeKey === '2') {
// 手机验证码登录
this.$message.warning('暂未开发')
}
},
regist () {
this.$emit('regist', 'Regist')
},
authentication () {
let authorUrl = this.userAuthorizationUri
authorUrl = authorUrl + ('?' + Qs.stringify({
loginStyle: this.loginStyle,
client_id: this.client_id,
response_type: this.response_type,
scope: this.scope,
redirect_uri: this.redirect_uri,
state: this.state
}))
window.location.href = authorUrl
},
getCaptcha () {
this.$message.warning('暂未开发')
},
handleTabsChange (val) {
this.activeKey = val
},
...mapMutations({
setToken: 'account/setToken',
setExpireTime: 'account/setExpireTime',
setPermissions: 'account/setPermissions',
setRoles: 'account/setRoles',
setUser: 'account/setUser',
setTheme: 'setting/setTheme',
setLayout: 'setting/setLayout',
setMultipage: 'setting/setMultipage',
fixSiderbar: 'setting/fixSiderbar',
fixHeader: 'setting/fixHeader',
setColor: 'setting/setColor'
}),
saveLoginData (data) {
this.setToken(data.token)
this.setExpireTime(data.exipreTime)
this.setUser(data.user)
this.setPermissions(data.permissions)
this.setRoles(data.roles)
this.setTheme(data.config.theme)
this.setLayout(data.config.layout)
this.setMultipage(data.config.multiPage === '1')
this.fixSiderbar(data.config.fixSiderbar === '1')
this.fixHeader(data.config.fixHeader === '1')
this.setColor(data.config.color)
console.log(data.permissions)
console.log(data.user.username)
console.log(data.config.fixSiderbar)
console.log(data.config.fixHeader)
}
},
mounted () {
let authCodeURL = window.location.href
this.code = authCodeURL.substring(authCodeURL.indexOf('code'), authCodeURL.indexOf('&'))
this.$post('authLogin', {
code: this.code
}).then((r) => {
let data = r.data.data
console.log('data:' + data)
this.saveLoginData(data)
this.loading = false
this.$router.push('/')
}).catch(() => {
setTimeout(() => {
this.loading = false
}, 500)
})
}
}
</script>
<style lang="less" scoped>
.login {
.icon {
font-size: 24px;
color: rgba(0, 0, 0, 0.2);
margin-left: 16px;
vertical-align: middle;
cursor: pointer;
transition: color 0.3s;
&:hover {
color: #1890ff;
}
}
}
</style>
4.前段拿到授权码去后台申请令牌获取资源
package com.ftsafe.rapido.system.controller;
import com.ftsafe.entity.RapidoOnlineUserEntity;
import com.ftsafe.rapido.common.annotation.Limit;
import com.ftsafe.rapido.common.authentication.JWTToken;
import com.ftsafe.rapido.common.authentication.JWTUtil;
import com.ftsafe.rapido.common.domain.ActiveUser;
import com.ftsafe.rapido.common.domain.RapidoConstant;
import com.ftsafe.rapido.common.domain.RapidoResponse;
import com.ftsafe.rapido.common.exception.RapidoException;
import com.ftsafe.rapido.common.properties.RapidoProperties;
import com.ftsafe.rapido.common.service.RedisService;
import com.ftsafe.rapido.common.utils.*;
import com.ftsafe.rapido.system.dao.LoginLogMapper;
import com.ftsafe.rapido.system.domain.LoginLog;
import com.ftsafe.rapido.system.domain.User;
import com.ftsafe.rapido.system.domain.UserConfig;
import com.ftsafe.rapido.system.manager.UserManager;
import com.ftsafe.rapido.system.service.LoginLogService;
import com.ftsafe.rapido.system.service.UserService;
import com.ftsafe.service.IRapidoBussinessService;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthResourceResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
@Validated
@RestController
public class LoginController {
@Autowired
private RedisService redisService;
@Autowired
private UserManager userManager;
@Autowired
private UserService userService;
@Autowired
private LoginLogService loginLogService;
@Autowired
private LoginLogMapper loginLogMapper;
@Autowired
private RapidoProperties properties;
@Autowired
private ObjectMapper mapper;
@Reference(version = "${rapido.service.version}",
application = "${dubbo.application.id}",
retries = -1,
interfaceClass = IRapidoBussinessService.class)
private IRapidoBussinessService rapidoBussinessService;
@PostMapping("/authLogin")
@Limit(key = "authLogin", period = 60, count = 20, name = "登录认证接口", prefix = "limit")
public RapidoResponse authLogin(
@NotBlank(message = "{required}") String code, HttpServletRequest request) throws Exception {
final String errorMessage = "获取登录认证错误";
String userInfoStr = "";
String token = "";
//令牌
code = code.substring(code.indexOf("=")+1);
//设置请求令牌请求求信息
OAuthClientRequest accessTokenRequest = OAuthClientRequest.
tokenLocation(RapidoConstant.OAUTH_CLIENT_ACCESS_TOKEN).
setGrantType(GrantType.AUTHORIZATION_CODE).
setClientId(RapidoConstant.OAUTH_CLIENT_ID).
setClientSecret(RapidoConstant.OAUTH_CLIENT_SECRET).
setCode(code).
setRedirectURI(RapidoConstant.OAUTH_CLIENT_CALLBACK).
buildQueryMessage();
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);
//token令牌
token = oAuthResponse.getAccessToken();
Long expiresln = oAuthResponse.getExpiresIn();//过期时间
if(StringUtils.isEmpty(token)){
throw new RapidoException("获取令牌错误");
}
if(null == expiresln){
throw new RapidoException("令牌已过期或失效");
}
//设置获取资源请求头信息
OAuthClientRequest userInfoRequest = new OAuthBearerClientRequest(RapidoConstant.OAUTH_CLIENT_USER_INFO).setAccessToken(token).buildQueryMessage();
userInfoRequest.setHeader("Authorization", "Bearer "+token);
OAuthResourceResponse resourceResponse = oAuthClient.resource(userInfoRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class);
userInfoStr = resourceResponse.getBody();
if(StringUtils.isEmpty(userInfoStr)){
throw new RapidoException("获取资源失败");
}
User user = JSONObject.parseObject(userInfoStr , User.class);// jsonStr 是String类型。
User auUser = this.userManager.getUser(user.getUsername());
auUser.setFullUserName(user.getFullUserName());
auUser.setEmail(user.getEmail());
// 更新用户登录时间
this.userService.updateLoginTime(auUser.getUsername());
// 保存登录记录
LoginLog loginLog = new LoginLog();
loginLog.setUsername(user.getUsername());
this.loginLogService.saveLoginLog(loginLog);
//token有效期
Date du = new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
long expiresa = du.getTime() + expiresln*1000;
//token加密
token = RapidoUtil.encryptToken(JWTUtil.sign(user.getUsername(), "1de0f8a155afee2bf642bb57e38bc188"));
JWTToken tokenObj = new JWTToken(token,String.valueOf(df.format(expiresa)));
//设置redis
String userId = this.saveTokenToRedis(user, tokenObj, request);
auUser.setId(userId);
Map<String, Object> userInfo = this.generateUserInfo(tokenObj, auUser);
return new RapidoResponse().message("认证成功").data(userInfo);
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)