登录
Token(涉及JWT、HTTPS、请求头、Cookie/localstorage)
后台管理系统的登录权限设计通常会使用 token 来实现。下面是一个常见的设计方案:
- 用户登录:用户在登录页面输入用户名和密码后,后台验证用户信息是否正确。如果验证通过,后台会生成一个 token,并将其返回给前端。
- Token 生成:Token 是一个包含用户身份信息的字符串,通常使用
JWT(JSON Web Token)来生成。JWT 由三部分组成:头部、载荷和签名。头部包含算法和类型信息,载荷包含用户的身份信息和其他自定义信息,签名用于验证 Token 的完整性。 - Token 传递:后台将生成的 Token 返回给前端,前端通常会将 Token 存储在客户端的
Cookie 或者本地存储中。 - 请求验证:用户在后续的请求中,通过
axios请求拦截器进行拦截,每次请求的时候头部携带token。后台在接收到请求后,会验证 Token 的合法性和有效期。 - Token 验证:后台会对收到的 Token 进行解析和验证。验证过程包括检查 Token 的签名是否正确、Token 是否过期以及用户权限等。
- 有效期管理:为了保证安全性,Token 通常会设置一个有效期,可以是固定的时间,也可以是根据用户的操作动态延长。在有效期过期之后,用户需要重新登录获取新的 Token。如果放在cookies里面,当浏览器关闭了就丢失了。重新打开浏览器都需要重新登录验证,后端也会在每周固定一个时间点重新刷新token,让后台用户全部重新登录一次,确保后台用户不会因为电脑遗失或者其它原因被人随意使用账号。
会话级别的 Cookie:如果不设置过期时间,Cookie 将成为会话级别的 Cookie,也就是说,它将在用户关闭浏览器时自动过期。这种类型的 Cookie 仅在用户当前会话期间有效,一旦用户关闭浏览器,该 Cookie 将被删除。
持久性 Cookie:可以通过设置过期时间来创建持久性 Cookie。过期时间可以是一个具体的日期和时间,或者是一个相对于当前时间的时间间隔。一旦设置了过期时间,浏览器将在过期时间到达后自动删除该 Cookie。
- Token 存储:后台通常会将 Token 存储在服务器端的内存、数据库或者缓存中。存储的方式取决于具体的应用需求和技术架构。
需要注意的是,为了保证安全性,Token 在传输过程中应该使用HTTPS进行加密传输,以防止被中间人窃取或篡改。此外,为了防止 Token 被盗用,可以使用一些额外的安全措施,如限制 Token 的使用范围、定期更换 Token 等。
Session
Session 登录是一种常见的用户认证和授权机制,它在 Web 应用程序中被广泛使用。基本工作原理:
- 用户登录:用户在登录页面输入用户名和密码后,后台验证用户信息是否正确。如果验证通过,后台会创建一个
会话(session)并为该会话分配一个唯一的会话 ID。 - 会话管理:后台会将
会话 ID 存储在服务器端,并将其发送给客户端。通常,会话 ID 会被存储在一个名为sessionID的 Cookie 中,或者通过URL 参数的方式传递给客户端。 - 请求验证:用户在后续的请求中,会
携带会话 ID。后台在接收到请求后,会根据会话 ID 来识别用户,并验证用户的身份和权限。 - 会话状态维护:后台会使用会话 ID 来维护用户的登录状态。会话对象中可以保存一些用户相关的信息,如用户 ID、角色、权限等。在后续的请求中,后台可以通过会话 ID 来获取用户的信息,以便进行权限验证和业务处理。
- 会话过期:为了保证安全性,会话通常会设置一个有效期。在有效期过期之后,用户需要重新登录获取新的会话。
- 会话存储:会话对象通常会被存储在服务器端的内存、数据库或者缓存中。存储的方式取决于具体的应用需求和技术架构。
需要注意的是,Session 登录是基于服务器端的会话管理,因此需要在服务器端进行会话状态的维护和验证。相比于 Token 登录,Session 登录的主要特点是会话状态存储在服务器端,相对更安全,但也需要服务器端进行额外的存储和管理。
权限管理
用户——角色——权限 RBAC(Role-Based Access Control)模型
- 定义角色和权限:首先,需要定义不同的角色和对应的权限。角色可以根据用户的职责和权限等级来划分,例如管理员、普通用户、编辑等。权限可以是系统中的具体功能或操作,如添加、编辑、删除等。
- 分配权限给角色:将定义好的权限分配给相应的角色。可以通过界面或配置文件等方式,将权限与角色进行关联。
- 用户角色关联:将用户与相应的角色进行关联。当用户登录系统时,系统会根据用户的角色来确定其具有的权限。
- 权限验证:在系统的各个功能模块中,需要进行权限验证。当用户访问某个功能时,系统会检查用户所属的角色是否具有相应的权限,如果没有权限,则禁止用户执行该操作或访问该页面。
- 后台管理界面:为了方便管理和配置权限,可以开发一个后台管理界面,供管理员进行权限的设置和管理。管理员可以通过该界面添加、编辑、删除角色和权限,以及分配权限给角色。
- 日志记录:为了安全和追溯,建议在系统中记录用户的操作日志。可以记录用户的登录、权限变更等操作,以便后续审计和追踪。
动态路由
通过token获取用户对应的 role,动态根据用户的 role 获取其对应有权限的路由数组,(中间处理数据将后台返回的数据映射成路由)通过 router.addRoutes 动态挂载这些路由。
上述所有的数据和操作都是通过vuex全局管理控制的。(刷新页面后 vuex的内容也会丢失,所以需要重复上述的那些操作,或者将数据保存在本地刷新时自动加载本地数据)
封装请求 axios
切换环境
我们的项目环境可能有开发环境、测试环境和生产环境。 我们通过node的环境变量来匹配我们的默认的接口url前缀。 axios.defaults.baseURL可以设置axios的默认请求地址。
// 环境的切换
if (process.env.NODE_ENV == 'development') {
axios.defaults.baseURL = 'https://www.baidu.com';}
else if (process.env.NODE_ENV == 'debug') {
axios.defaults.baseURL = 'https://www.ceshi.com';
}
else if (process.env.NODE_ENV == 'production') {
axios.defaults.baseURL = 'https://www.production.com';
}
请求拦截
import store from '@/store/index';
// 请求拦截器
axios.interceptors.request.use(
config => {
const token = store.state.token;
token && (config.headers.Authorization = token); //请求头增加 token
return config;
},
error => {
return Promise.error(error);
})
响应的拦截
axios.interceptors.response.use(
response => {
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
// 否则的话抛出错误
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
// 服务器状态码不是2开头的的情况
// 这里可以跟你们的后台开发人员协商好统一的错误状态码
// 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等
// 下面列举几个常见的操作,其他需求可自行扩展
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
break;
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
Toast({
message: '登录过期,请重新登录',
duration: 1000,
forbidClick: true
});
// 清除token
localStorage.removeItem('token');
store.commit('loginSuccess', null);
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
// 404请求不存在
case 404:
Toast({
message: '网络请求不存在',
duration: 1500,
forbidClick: true
});
break;
// 其他错误,直接抛出错误提示
default:
Toast({
message: error.response.data.message,
duration: 1500,
forbidClick: true
});
}
return Promise.reject(error.response);
}
}
});
post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
封装get方法和post方法
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function get(url, params){
return new Promise((resolve, reject) =>{
axios.get(url, {
params: params
}).then(res => {
resolve(res.data);
}).catch(err =>{
reject(err.data)
})
});}
post方法必须要使用对提交从参数对象进行序列化的操作,所以这里我们通过node的qs模块来序列化我们的参数。这个很重要,如果没有序列化操作,后台是拿不到你提交的数据的。
import QS from 'qs';
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function post(url, params) {
return new Promise((resolve, reject) => {
axios.post(url, QS.stringify(params))
.then(res => {
resolve(res.data);
})
.catch(err =>{
reject(err.data)
})
});
}复制代码
后台管理系统的开发和维护可能面临以下一些难点:
- 复杂的业务逻辑:后台管理系统通常需要处理大量的业务逻辑,包括权限管理、数据管理、用户管理等。这些业务逻辑可能相互关联,且涉及到复杂的数据操作和业务规则,需要开发人员具备深入的业务理解和设计能力。
- 多角色权限管理:后台管理系统通常需要支持多角色的权限管理,不同角色的用户可能具有不同的操作权限和数据访问权限。实现灵活且安全的权限管理是一个挑战,需要考虑角色的细粒度控制、权限的动态分配和管理等。
- 数据可视化和报表:后台管理系统通常需要提供数据可视化和报表功能,以便管理员能够直观地查看和分析数据。这需要开发人员具备数据分析和可视化技术的能力,并能够设计和实现复杂的数据报表和图表。
- 性能和扩展性:后台管理系统通常需要处理大量的数据和用户请求,因此性能和扩展性是关键考虑因素。开发人员需要优化数据库查询、缓存策略和系统架构,以确保系统能够高效地处理大规模的数据和并发请求。
- 用户体验和界面设计:后台管理系统虽然主要面向管理员和运营人员,但良好的用户体验和界面设计仍然是重要的。开发人员需要考虑用户操作的便捷性、界面的友好性和响应速度,以提高用户的工作效率和满意度。
- 安全性和数据保护:后台管理系统通常涉及敏感的用户数据和业务信息,因此安全性和数据保护是至关重要的。开发人员需要采取合适的安全措施,如用户认证、数据加密、访问控制等,以保护系统和用户数据的安全。
以上只是一些常见的难点,实际的后台管理系统开发中还可能面临其他具体的挑战,需要根据具体的业务需求和技术要求来解决。