目录
项目搭建:
根据官方文档
前端mall4cloud-platform-master:
需求:
用户登录成功跳转到用户界面,token过期跳转到登录页面,后端配置用户的权限页面
技术
vuex状态管理: 简单的理解就是一个全局的数据存储。
路由: 你配置了路径,view就可以转到你想要去的页面。
路由守卫:页面跳转的时候,可以做一个拦截的作用。
基本实现思路:用户登录的时候保存一个token到store里面,跳转到首页, 每一次页面跳转的时候路由守卫就检测,是否有token,是否有权限。
开发环境跨域解决
vue.config.js开启代理。
devServer: {
proxy:{
'/dycloud-auth':{ //请求的api 例如请求是 http://localhost:8080/dycloud-rbac/role/page
target:"http://localhost:8000", // 网关地址
ws:true,
changeOrigin:true
},
'/dycloud-platform':{
target:"http://localhost:8000",
ws:true,
changeOrigin:true
},
'/dycloud-rbac':{
target:"http://localhost:8000",
ws:true,
changeOrigin:true
},
}
},
代码实现:
点击登录按钮的时候
login(verifyResult) {
console.log(verifyResult.captchaVerification)
this.loading = true
this.loginInfo.captcha = verifyResult.captchaVerification
调用store login动作 login里面又请求了登录接口,并且将token保存到store
this.$store.dispatch('user/login', this.loginInfo)
.then(() => {
重定向
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
this.loading = false
})
.catch((e) => {
console.log(e)
this.loading = false
})
},
发出重定向指令的时候会先去路由守卫判断。
如果存在token
if (hasToken) {
console.log("路径")
console.log(to.path)
如果当前页面是login 也就是你点击的是登录页
if (to.path === '/login') {
// 放行到主页
next({ path: '/' })
NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
} else {
// debugger
// determine whether the user has obtained his permission roles through getInfo
如果有角色直接放行
if (hasRoles) {
next()
} else {
try {
// 调用后端接口 获取用户信息 和权限,保存到store里面
const userInfo = await store.dispatch('user/getUserInfo')
// 获取权限信息
store.dispatch('user/listPermissions')
let menuIds = []
if (!userInfo.isAdmin) {
// 获取菜单信息
menuIds = await store.dispatch('user/listMenuIds')
}
// 获取当前用户的菜单列表
const accessRoutes = await store.dispatch('permission/generateRoutes', menuIds)
// 404页面放入路由
accessRoutes.push({ path: '*', redirect: '/404', hidden: true })
// 将后端配置的路由放入路由
router.addRoutes(accessRoutes)
放行
next({ ...to, replace: true })
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
}
注意点:用户首次登录只设置了token,没有角色。所以此时一定会执行到else里面,去查询角色,菜单权限。
store里面的数据也是响应双向的。
下面是store代码
login({ commit }, userInfo) {
const { username, password, captcha } = userInfo
return new Promise((resolve, reject) => {
login({ principal: username.trim(), credentials: password, captchaVerification: captcha, sysType: 2 }).then(response => {
commit('SET_TOKEN', response.accessToken)
setToken(response.accessToken)
resolve()
}).catch(error => {
reject(error)
})
})
},
// get permissions
listPermissions({ commit, state }) {
return new Promise((resolve, reject) => {
if (state.isAdmin) {
commit('SET_ROLES', [''])
resolve([''])
return
}
menuPermissionsList().then(permissions => {
console.log(permissions)
if (!permissions) {
reject('Verification failed, please Login again.')
}
// roles must be a non-empty array
if (!permissions || permissions.length <= 0) {
permissions = ['']
}
commit('SET_ROLES', permissions)
resolve(permissions)
}).catch(error => {
reject(error)
})
})
},
后端:
权限校验过程,在commom,security AuthFilter下面。
设计思路:
用户先请求一个登录接口:获取token,并且token和用户信息绑定。
后面每一次请求,都去查看一下token,和用户权限有没有问题。
所以需要检测token的接口,和用户权限的接口.
硬件方面看。首先经过网关服务器,请求到登录接口获取到token。此时前端拿到token了,前端后续请求,因为不确定客户端要请求哪一个服务,所有做一个公共的拦截器,去检测token和权限问题。
做一个sverlet拦截器。
定义服务器内部feign请求都是以 /feign开始
定义白名单ip
定义无须拦截的请求地址 登录接口就无需拦截
实现思路:
首先需要定义token,和权限检测接口。具体实现交给其他服务。
1.验证http请求,uri,如果是feign请求,则验证key, secret凭证(就是验证服务器保存一份,其他服务器请求的时候放在header里面,再进行一下对比)
2.查看设置的白名单,如果有白名单则,则验证请求是否在白名单里面。
上述验证未通过,则抛出异常。
3.如果是检测token的请求,则放行。
4.放行配置中无需权限校验的uri
5.token校验 token和用户信息需要绑定,调用token接口
6.用户权限校验 调用权限接口
7.为了便于在控制器里面获取用户信息,使用ThreadLocal保存起来
8.整个http结束,清除token信息。
token授权服务:
首先是登录,去数据库里面查用户信息。
生成一个token 用uuid就行
然后建立token 和用户信息的关系,存储到redis中,redis可以设置过期时间,所以token的过期时间也解决了。
token加密返回给前端。
token校验:
我们是一个微服务,所以每一http,其他服务器都会请求授权服务校验一下token。
所以是一个feign接口,公共包也定义了这个请求。
校验过程就很简单了,登录已经录入了数据,校验再根据token取数据就行了。
用户权限服务:
用户,角色,权限,菜单。管理项目,和token校验一样是单独的一个服务。
代码实现
公共包下面定义一个权限包,做http拦截,以后那个项目需要权限引入就行。
api中定义,权限的接口。检查token,检查权限。 由具体的服务去实现,只定义标准。所以以后想换一个认证服务,权限管理服务,也很简单。
接口具体的实现
总结 :
前端:登录再进入菜单,整个流程是怎么样子的。涉及到的技术,请求,状态管理,路由拦截,路由。
后端:token是怎么生成的?每一次请求是怎么校验token,权限的?。