欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

token与用户权限-前端权限控制-RBAC模型

程序员文章站 2022-07-14 15:32:49
...

token与用户权限-前端权限控制-RBAC模型


目录




内容

完整的权限控制包括后端和前端,这里我们先分析下前端。

1、登录和token携带

关于token的生成和解析,这里不再详述,可以看我上一篇博文,这里主要讲解下登录和登录成功后返回token.

1.1、 登录

登录流程:

  1. 前端发送登录表单:手机号+密码

    • 未避免密码明文传输,这里我们直接md5加密
    1. npm install js-md5
    2. md5(password) 完成MD5加密就这么简单
    
  2. 后端接收:map接收

  3. 登录校验

    1. 根据手机号查询用户
      1. 不存在:提示用户名或者密码错误
    2. 校验密码
      1. 不存在:提示用户名或者密码错误
  4. 生成token返回

  5. 接收token存储到vuex store和cookie中

    1. vuex store token 每次从cookie获取
  6. 路由请求拦截器,每次发送请求携带token

    1. 判断是否有token
      1. 有就在请求头中携带
  • 后端实现代码:

       @Override
      public String login(Map<String, Object> map) {
    
      	String mobile = (String) map.get("mobile");
      	String password = (String) map.get("password");
      	UserEntity userEntity = userDao.selectOne(new QueryWrapper<UserEntity>().eq("mobile", mobile));
    
      	if ( userEntity == null || !StringUtils.equals(password, userEntity.getPassword())) {
      		throw new RRException("用户名或者密码错误");
      	}
      	Map<String, Object> m = new HashMap<>();
      	m.put("companyId", userEntity.getCompanyId());
      	m.put("companyName", userEntity.getCompanyName());
      	m.put("userId", userEntity.getId());
      	return jwtUtils.createJwt(userEntity.getId(), userEntity.getUsername(), m);
      }
    
  • 前端

    • 登录和token 获取

        login({ commit }, userInfo) {
        	const { mobile, password } = userInfo
        	return new Promise((resolve, reject) => {
        	  login({ mobile: mobile.trim(), password: password }).then(response => {
        		console.log(response, 'res');
        		const { token } = response
        		commit('SET_TOKEN', token)
        		setToken(token)
        		resolve()
        	  }).catch(error => {
        		reject(error)
        	  })
        	})
          },
      
    • 请求头携带token

        service.interceptors.request.use(
          config => {
        	if (store.getters.token) {
        	  config.headers['Authorization'] = getToken()
        	}
        	return config
          },
          error => {
        	console.log(error) 
        	return Promise.reject(error)
          }
        )
      

2、用户信息(权限信息)获取和存储

要实现前端权限校验,登录成功后,菜单和按钮权限是必须。

获取步骤:

  1. 登录成功后,请求用户信息
    1. 携带token,token中携带userId

  2. 根据用户id,获取菜单权限

    1. 菜单权限为2级层级数据
    2. 符合前端路由要求
  3. 按钮权限获取

    1. 为字符串集合
  4. 前端接收和存储

    1. 接收后存储vuex store中
  • 后端代码

    • 获取个人信息

        @Override
        	public Map<String, Object> profile(String token) {
      
        		// 解析token,获取claims
        		Claims claims = jwtUtils.parseJwt(token);
                System.out.println(claims);
        //        String id = claims.getId();
        //        Object o = claims.get("jti");
        		String userId = (String) claims.get("userId");
        //        System.out.println(claims.get("userId"));
      
        		// 获取用户信息
        		UserEntity userEntity = userDao.selectById(userId);
        		// 根据用户id获取权限
        		// 获取菜单权限
        		List<PermissionEntity> menus = queryLevelMenusByUserId(userId);
        		// 获取按钮权限
        		List<String> btns = permissionDao.queryBtnsByUserId(userId);
      
        		Map<String, Object> userInfo  = new HashMap<>();
        		userInfo.put("user", userEntity);
        		if (CollectionUtils.isNotEmpty(menus)) {
        			userInfo.put("menus", menus);
        		}
        		if (CollectionUtils.isNotEmpty(btns)) {
        			userInfo.put("btns", btns);
        		}
        	   return userInfo;
        	}
      
    • 获取菜单

        private List<PermissionEntity> queryLevelMenusByUserId(String id) {
      
        		List<PermissionEntity> menus = permissionDao.queryMenusByUserId(id);
      
        		// 1、如果是集合为空结束
        		if (CollectionUtils.isEmpty(menus)) {
        			return null;
        		}
        		PermissionEntity root = new PermissionEntity();
        		root.setId("0");
        		LinkedList<PermissionEntity> stack = new LinkedList<>();
        		stack.push(root);
      
        		while (!stack.isEmpty() && menus.size() > 0) {
        			PermissionEntity m = stack.pop();
        			List<PermissionEntity> children = new LinkedList<>();
        			Iterator<PermissionEntity> iterator = menus.iterator();
        			while (iterator.hasNext()) {
        				PermissionEntity next = iterator.next();
        				if (StringUtils.equals(m.getId(),next.getPid())) {
        					// 2.1、找到元素,加入子集合;同时删除在原有集合中移除
        //                    next.setParent(m);
        					children.add(next);
        					iterator.remove();
        				}
        			}
        			if (children.size() > 0) {
        				// 3、子集合不为空,封装层级数据
      
        				m.setChildren(children);
        				stack.addAll(children);
        //                for (PermissionEntity x: children) {
        //                    stack.push(x);
        //                }
        			}
        		}
        		return root.getChildren();
        	}
      
    • 获取按钮权限

        <select id="queryBtnsByUserId" resultType="java.lang.String">
        		select
        			tp.perms
        		from tb_permission tp
        		left join tb_role_perm trp on trp.perm_id = tp.id
        		left join tb_user_role tur on tur.role_id = trp.role_id
        		where tur.user_id = #{id} and type = 2
        	</select>
      
  • 前端

    • 把个人信息存储到store中

       getInfo({ commit, state }) {
       	return new Promise((resolve, reject) => {
       	  getInfo(state.token).then(response => {
       		console.log(response, 'info');
       		const { userInfo } = response
       		const {user, menus, btns} = userInfo
       		if (!user) {
       		  reject('认证失败,请重新登录')
       		}
      
       		// const { roles, name, avatar, introduction } = data
      
       		// roles must be a non-empty array
       		if (!menus || menus.length <= 0) {
       		  reject('权限不能为空,请先获取权限')
       		}
      
       		commit('SET_MENUS', menus)
       		commit('SET_BTNS', btns)
       		commit('SET_USER', user)
      
       		resolve(userInfo)
       	  }).catch(error => {
       		reject(error)
       	  })
       	})
         },
      

到此我们登录和前端权限控制所需信息获取已完成,下面我要实现前端动态菜单的生成。

后记

本项目为参考某马视频开发,相关视频及配套资料可自行度娘或者联系本人。上面为自己编写的开发文档,持续更新。欢迎交流,本人QQ:806797785

后端JAVA源代码地址:https://gitee.com/gaogzhen/ihrm-parent    // 后端项目
前端项目源代码地址:https://gitee.com/gaogzhen/ihrm-vue    // 前端后台管理系统