Authorization

This commit is contained in:
Maxim Filippov 2019-02-22 22:38:56 +03:00
parent 83fc9e6aa8
commit 96e52a14cc
11 changed files with 67 additions and 153 deletions

View file

@ -57,7 +57,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
template: 'index.html',
inject: true,
favicon: resolve('favicon.ico'),
title: 'vue-element-admin',
title: 'Admin FE',
templateParameters: {
BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory,
},

View file

@ -55,7 +55,7 @@ const webpackConfig = merge(baseWebpackConfig, {
template: 'index.html',
inject: true,
favicon: resolve('favicon.ico'),
title: 'vue-element-admin',
title: 'Admin FE',
templateParameters: {
BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory,
},

View file

@ -1,5 +1,5 @@
module.exports = {
NODE_ENV: '"development"',
ENV_CONFIG: '"dev"',
BASE_API: '"https://api-dev"'
BASE_API: '"http://localhost:4000"'
}

View file

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>vue-element-admin</title>
<title>Admin FE</title>
</head>
<body>
<script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script>

View file

@ -1,29 +1,42 @@
import request from '@/utils/request'
export function loginByUsername(username, password) {
const data = {
username,
password
}
return request({
url: '/login/login',
export async function loginByUsername(username, password) {
const appsRequest = await request({
url: '/api/v1/apps',
method: 'post',
data
data: {
client_name: `AdminFE_${Math.random()}`,
redirect_uris: `${window.location.origin}/oauth-callback`,
scopes: 'read write follow'
}
})
const app = appsRequest.data
return request({
url: '/oauth/token',
method: 'post',
data: {
client_id: app.client_id,
client_secret: app.client_secret,
grant_type: 'password',
username: username,
password: password
}
})
}
export function logout() {
export function getUserInfo() {
return request({
url: '/login/logout',
url: '/api/account/verify_credentials',
method: 'post'
})
}
export function getUserInfo(token) {
return request({
url: '/user/info',
method: 'get',
params: { token }
})
export function logout() {
}
const oauth = { loginByUsername, getUserInfo, logout }
export default oauth

View file

@ -63,7 +63,8 @@ export default {
theme: 'Theme',
clipboardDemo: 'Clipboard',
i18n: 'I18n',
externalLink: 'External Link'
externalLink: 'External Link',
users: 'Users'
},
navbar: {
logOut: 'Log Out',

View file

@ -26,7 +26,7 @@ router.beforeEach((to, from, next) => {
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
const roles = res.data.rights.admin ? ['admin'] : []
store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record

View file

@ -76,32 +76,6 @@ export const constantRouterMap = [
meta: { title: 'dashboard', icon: 'dashboard', noCache: true, affix: true }
}
]
},
{
path: '/documentation',
component: Layout,
redirect: '/documentation/index',
children: [
{
path: 'index',
component: () => import('@/views/documentation/index'),
name: 'Documentation',
meta: { title: 'documentation', icon: 'documentation', affix: true }
}
]
},
{
path: '/guide',
component: Layout,
redirect: '/guide/index',
children: [
{
path: 'index',
component: () => import('@/views/guide/index'),
name: 'Guide',
meta: { title: 'guide', icon: 'guide', noCache: true }
}
]
}
]
@ -112,6 +86,18 @@ export default new Router({
})
export const asyncRouterMap = [
{
path: '/users',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/users/index'),
name: 'Users',
meta: { title: 'users', icon: 'peoples', noCache: true }
}
]
},
{
path: '/permission',
component: Layout,

View file

@ -44,14 +44,13 @@ const user = {
},
actions: {
// 用户名登录
LoginByUsername({ commit }, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
loginByUsername(username, userInfo.password).then(response => {
const data = response.data
commit('SET_TOKEN', data.token)
setToken(response.data.token)
commit('SET_TOKEN', data.access_token)
setToken(response.data.access_token)
resolve()
}).catch(error => {
reject(error)
@ -59,25 +58,25 @@ const user = {
})
},
// 获取用户信息
GetUserInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getUserInfo(state.token).then(response => {
// 由于mockjs 不支持自定义状态码只能这样hack
if (!response.data) {
reject('Verification failed, please login again.')
}
const data = response.data
if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', data.roles)
if (data.rights) {
if (data.rights.admin) {
commit('SET_ROLES', ['admin'])
}
} else {
reject('getInfo: roles must be a non-null array!')
}
commit('SET_NAME', data.name)
commit('SET_AVATAR', data.avatar)
commit('SET_INTRODUCTION', data.introduction)
commit('SET_AVATAR', data.profile_image_url)
commit('SET_INTRODUCTION', '')
resolve(response)
}).catch(error => {
reject(error)

View file

@ -12,10 +12,8 @@ const service = axios.create({
// request interceptor
service.interceptors.request.use(
config => {
// Do something before request is sent
if (store.getters.token) {
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
config.headers['X-Token'] = getToken()
config.headers['Authorization'] = `Bearer ${getToken()}`
}
return config
},

View file

@ -1,11 +1,10 @@
<template>
<div class="login-container">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
<el-form ref="loginForm" :model="loginForm" class="login-form" auto-complete="on" label-position="left">
<div class="title-container">
<h3 class="title">
{{ $t('login.title') }}
</h3>
<lang-select class="set-language" />
</div>
<el-form-item prop="username">
@ -41,66 +40,18 @@
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">
{{ $t('login.logIn') }}
</el-button>
<div style="position:relative">
<div class="tips">
<span>{{ $t('login.username') }} : admin</span>
<span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
</div>
<div class="tips">
<span style="margin-right:18px;">
{{ $t('login.username') }} : editor
</span>
<span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
</div>
<el-button class="thirdparty-button" type="primary" @click="showDialog=true">
{{ $t('login.thirdparty') }}
</el-button>
</div>
</el-form>
<el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog">
{{ $t('login.thirdpartyTips') }}
<br>
<br>
<br>
<social-sign />
</el-dialog>
</div>
</template>
<script>
import { isvalidUsername } from '@/utils/validate'
import LangSelect from '@/components/LangSelect'
import SocialSign from './socialsignin'
export default {
name: 'Login',
components: { LangSelect, SocialSign },
data() {
const validateUsername = (rule, value, callback) => {
if (!isvalidUsername(value)) {
callback(new Error('Please enter the correct user name'))
} else {
callback()
}
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('The password can not be less than 6 digits'))
} else {
callback()
}
}
data: function() {
return {
loginForm: {
username: 'admin',
password: '1111111'
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
username: '',
password: ''
},
passwordType: 'password',
loading: false,
@ -116,12 +67,6 @@ export default {
immediate: true
}
},
created() {
// window.addEventListener('hashchange', this.afterQRScan)
},
destroyed() {
// window.removeEventListener('hashchange', this.afterQRScan)
},
methods: {
showPwd() {
if (this.passwordType === 'password') {
@ -131,47 +76,19 @@ export default {
}
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
this.loading = false
this.$router.push({ path: this.redirect || '/' })
}).catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
this.loading = true
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
this.loading = false
this.$router.push({ path: this.redirect || '/' })
}).catch(() => {
this.loading = false
})
},
afterQRScan() {
// const hash = window.location.hash.slice(1)
// const hashObj = getQueryObject(hash)
// const originUrl = window.location.origin
// history.replaceState({}, '', originUrl)
// const codeMap = {
// wechat: 'code',
// tencent: 'code'
// }
// const codeName = hashObj[codeMap[this.auth_type]]
// if (!codeName) {
// alert('')
// } else {
// this.$store.dispatch('LoginByThirdparty', codeName).then(() => {
// this.$router.push({ path: '/' })
// })
// }
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#eee;
$cursor: #fff;