前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue-element-admin整合spring-boot权限设计之实现用户授权功能

vue-element-admin整合spring-boot权限设计之实现用户授权功能

作者头像
用户3587585
发布2021-09-08 14:21:06
8510
发布2021-09-08 14:21:06
举报
文章被收录于专栏:阿福谈Web编程

前言

这篇文章笔者紧接着上一篇权限设计的文章vue-element-admin整合spring-boot实现权限控制之用户管理篇

我们来实现给用户添加与删除角色的功能。本文的功能实现依赖于笔者上传到gitee上的两个前后端项目,分别是江南一点雨开源的blog-server项目和花裤衩开源的vue-element-admin项目,文末会附上笔者提交到gitee上的源项目地址。

1 实现后端接口开发

1.1 查询用户未授权角色接口

1) Dao层代码开发

RolesMapper.java

代码语言:javascript
复制
List<Role> getUserNotAllocateRoles(Long uid);

RolesMapper.xml

代码语言:javascript
复制
<select id="getUserNotAllocateRoles" parameterType="java.lang.Long" resultType="org.sang.pojo.Role">
        SELECT r.id,
               r.role_code as roleCode,
               r.role_name as roleName
        FROM roles r
        where r.id not in
        (select rid
         from roles_user
         where uid = #{uid,jdbcType=BIGINT}
         )
    </select>

2) Service层代码

RoleService.java

代码语言:javascript
复制
public List<Role> getUserNotAllocateRoles(Long uid){
        List<Role> notAllocateRoles = rolesMapper.getUserNotAllocateRoles(uid);
        return notAllocateRoles;
    }

3)Controller层代码

代码语言:javascript
复制
@GetMapping("/userNotAllocateRoles")
    public RespBean getUserNotAllocateRoles(@RequestParam("uid") Long uid){
        logger.info("uid={}",uid);
        List<Role> roles = roleService.getUserNotAllocateRoles(uid);
        RespBean respBean = new RespBean(200, "success");
        respBean.setData(roles);
        return respBean;
    }

1.2 给用户添加角色接口

1) Dao层代码

RolesMapper.java

代码语言:javascript
复制
int setUserRoles(@Param("roleIds") List<Integer> roleIds, @Param("uid") Long uid);

RolesMapper.xml

代码语言:javascript
复制
<insert id="setUserRoles" keyProperty="id" useGeneratedKeys="true">
        INSERT INTO roles_user(rid,uid) VALUES
        <foreach collection="roleIds" item="roleId" separator=",">
            (#{roleId,jdbcType=INTEGER},#{uid,jdbcType=INTEGER})
        </foreach>
</insert>

2) Service层代码

代码语言:javascript
复制
public int addRolesForUser(List<Integer> roleIds, Long uid) {
        int count = rolesMapper.setUserRoles(roleIds, uid);
        return count;
    }

3) Controller层代

代码语言:javascript
复制
 @PostMapping(path = "/addRolesForUser")
    public RespBean addRolesForUser(@RequestBody List<Integer> roleIds, @RequestParam("uid") Long uid) {
        logger.info("uid={}",uid);
        int addCount = roleService.addRolesForUser(roleIds, uid);
        RespBean respBean = new RespBean(200, "success");
        respBean.setData(addCount);
        return respBean;
    }       

1.3 解除用户绑定角色接口

1) Dao层代码

RolesMapper.java

代码语言:javascript
复制
int delUserRoles(@Param("roleIds") List<Integer> roleIds, @Param("uid") Long uid);

RolesMapper.xml

代码语言:javascript
复制
    <delete id="delUserRoles">
        DELETE FROM roles_user where rid
        in <foreach collection="roleIds" item="roleId" open="(" close=")" separator=",">
               #{roleId, jdbcType=INTEGER}
           </foreach>
        and uid = #{uid, jdbcType=BIGINT}
    </delete>

2) Service层代码

RoleService.java

代码语言:javascript
复制
public int delUserRoles(List<Integer> roleIds, Long uid){
        int delCount = rolesMapper.delUserRoles(roleIds, uid);
        return delCount;
    }

3) Controller层代码

代码语言:javascript
复制
@DeleteMapping("/userRoles")
    public RespBean delUserRoles(@RequestBody List<Integer> roleIds, @RequestParam("uid") Long uid){
        logger.info("uid={}",uid);
        int delCount = roleService.delUserRoles(roleIds, uid);
        RespBean respBean = new RespBean(200, "success");
        respBean.setData(delCount);
        return respBean;
    }

以上每个接口完成开发后可启动后台服务器,通过postaman先调用登录接口,然后依次测试每个新开发的接口,之前的文章里有过很多如何使用postman这款API可视化工具测试接口,这里不再赘述。不懂的读者也可以通过CSDN博客搜索postman的具体用法。

2 实现前端视图组件与方法逻辑

2.1 前端添加新增接口方法

src/api/role.js文件中添加后台对应的三个接口的请求方法

代码语言:javascript
复制

/**
 * 查找用户未分配角色
 * @param {用户ID} uid
 * @returns Promise
 */
export function getUserNotAllocateRoles(uid) {
  return request({
    url: `/role/userNotAllocateRoles?uid=${uid}`,
    method: 'get'
  })
}

/**
 * 给用户添加角色
 * @param {要授权的角色ID集合} roleIds
 * @param {用户ID} uid
 * @returns Promise
 */
export function addRolesForUser(roleIds, uid) {
  return request({
    url: `/role/addRolesForUser?uid=${uid}`,
    method: 'post',
    data: roleIds
  })
}

/**
 * 删除用户角色
 * @param {要解除授权的角色ID集合} roleIds
 * @param {用户ID} uid
 * @returns Promise
 */
export function delRolesForUser(roleIds, uid) {
  return request({
    url: `/role/userRoles?uid=${uid}`,
    method: 'delete',
    data: roleIds
  })
}

2.2 用户管理组件添加分配角色对话框并绑定按钮方法

views/permission/UserManage.vue文件中的查看用户角色对话框下面添加类名为edit-dialog的分配角色对话框, 查询用户角色对话框也作了部分修改,对话框标题该为指定选中用户,同时在查询用户角色的对话框中可对用户进行解除绑定授权角色的操作。

代码语言:javascript
复制
<el-dialog class="query-dialog" :title="queryDialogTitle" :visible.sync="queryDialogVisible" 
      width="35%">
      <el-table ref="qeuryDialogTable" :data="userRoles" highlight-current-row 
        @current-change="handleCurrentRowChange" style="width: 100%" @select="checkRoles"
      >  
         <el-table-column type="selection" width="55">
         </el-table-column>
         <el-table-column property="id" label="角色ID" width="80">
         </el-table-column>
         <el-table-column property="roleCode" label="角色编码" width="120">
         </el-table-column>
         <el-table-column property="roleName" label="角色名称" width="120">
         </el-table-column>
      </el-table>
      <span slot="footer" class="dialog-footer">
        <el-button @click="closeQueryDialog">取 消</el-button>
        <el-button type="primary" @click="delUserRole">解除授权</el-button>
      </span>
    </el-dialog >
    <el-dialog class="edit-dialog" :title="editDialogTitle" :visible.sync="eidtDialogVisible" width="35%">
      <el-table ref="editDialogTable" :data="noAllocateRoles" highlight-current-row 
        style="width: 100%" tooltip-effect="dark"
        @selection-change="handleSelectionChange" @select="selectChecked">
         <el-table-column type="selection" width="55">
         </el-table-column>
         <el-table-column property="id" label="角色ID" width="80">
         </el-table-column>
         <el-table-column property="roleCode" label="角色编码" width="120">
         </el-table-column>
         <el-table-column property="roleName" label="角色名称" width="120">
         </el-table-column>
      </el-table>
      <span slot="footer" class="dialog-footer">
        <el-button @click="closeEidtDialog">取消</el-button>
        <el-button type="primary" @click="addUserRole">添加授权</el-button>
      </span> 
    </el-dialog>

<script>
    import {getRolesByUid, getUserNotAllocateRoles, addRolesForUser, delRolesForUser} from '@/api/role'
// 省略了上一篇文章中贴过的一部分js代码
export default {
  data() {
    return {
      queryDialogVisible: false,
      eidtDialogVisible: false,
      currentRoleRow: 0,
      selectedUid: null,
      queryDialogTitle: '',
      editDialogTitle: '',
      checkedRoles: [],
      multipleSelection: [],
      noAllocateRoles: [],
    }
  },
  methods: {
     openEditDialog(row){
          console.log(row)
          this.eidtDialogVisible = true
          const uid = row.id
          this.selectedUid = uid
          this.editDialogTitle = '给用户 '+row.nickname+' 添加角色'
          getUserNotAllocateRoles(uid).then(res=>{
            if(res.status===200 && res.data.status===200){
               this.noAllocateRoles = res.data.data
            }
          }).catch(err=>{
             console.error(err)
          })
    },
    handleSelectionChange(rows){
      
    },
    checkRoles(selection,row){
      this.checkedRoles = selection
    },
    selectChecked(selection,row){
      this.multipleSelection = selection
    },
    closeQueryDialog(){
      this.queryDialogVisible = false
    },
    handleCurrentRowChange(row){
      this.currentRoleRow = row
      this.$refs['qeuryDialogTable'].setCurrentRow(row)
    },
    closeEidtDialog(){
      this.eidtDialogVisible = false
    },
    addUserRole(){
        if (this.multipleSelection.length > 0) {
            let roleIds = []
            const uid = this.selectedUid
            for (let i = 0; i < this.multipleSelection.length; i++) {
                 let row = this.multipleSelection[i];
                 roleIds.push(row.id)
            }
            addRolesForUser(roleIds, uid).then(res=>{
               if (res.status===200 && res.data.status===200) {
                   this.$message({
                     showClose: true,
                     message: '授权角色成功',
                     type: 'success'
                   })
               }
            }).catch(err=>{
              this.$message({
                     showClose: true,
                     message: '授权角色成功失败',
                     type: 'error'
                   })
            })
        }else{
            this.$message({
              showClose: true,
              message: '请先选择授权的角色',
              type: 'warning'
            })
        }
        this.eidtDialogVisible = false
    },
    delUserRole() {
      if(this.checkedRoles.length > 0){
          let roleIds = []
          const uid = this.selectedUid
          for (let i = 0; i < this.checkedRoles.length; i++) {
                let row = this.checkedRoles[i];
                roleIds.push(row.id)
          }
          delRolesForUser(roleIds, uid).then(res=>{
              if(res.status===200 && res.data.status===200){
                  this.$message({
                     showClose: true,
                     message: '解除授权角色成功',
                     type: 'success'
                   })
               }
            }).catch(err=>{
               this.$message({
                     showClose: true,
                     message: '解除授权角色失败',
                     type: 'error'
                   })
            })
      }else{
        this.$message({
            showClose: true,
            message: '请先选择要解除授权的角色',
            type: 'warning'
        })
      }
      this.queryDialogVisible = false
    }
  }   
  }  
</script>

使用el-table组件中的select事件绑定方法拿到复选框中选中的角色数组,同时在data中使用一个selectedUid变量绑定当前用户ID,通过每一行用户的操作按钮进行绑定。

2.3 效果体验

通过在vue-element-admin前端项目的根目录下的控制台中执行npm run dev 运行本地开发环境服务器

代码语言:javascript
复制
App running at:
  - Local:   http://localhost:3000/
  - Network: http://192.168.1.235:3000/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

在浏览器中输入http://localhost:3000/ 输入用户名(heshengfu)和登录密码(heshengfu123)登录成功后进入系统首页,然后依次点击左侧的菜单栏的权限管理->用户管理进入用户管理界面

在右边的查询表单中点击事件范围输入框,在弹出的日期时间框左侧的快捷选项中选择最近三个月,点击确定按钮后,点击查询按钮出现如下用户数据界面

在第一行数据用户程序员阿福对应的操作行点击查看已有角色链接按钮,可看到页面打开了如下对话框:

选择对话框中的user角色对应的复选框,然后点击右边的解除授权,删除用户与user角色的绑定关系后,在关闭对话框后页面会弹出一个提示删除成功的消息

再次点击用户程序员阿福右边操作栏中的的增加授权角色按钮,页面打开给用户添加角色对话框

选中角色前面的复选框,然后点击右边的添加授权按钮,页面同样会弹出授权角色成功的消息提示框

好了,本文实现给用户添加授权和解除授权角色的功能就讲到这里了。

3 解决用户退出登录失败的bug

最近发现一个很严重的Bug, 那就是点击系统右上角下来框的退出按钮后,用户的缓存没有被删除,而后台调用接口的时候却提示用户未登录却没有跳转到用户登录页面去。后来启动浏览器开发者模式debugg定位才发现退出登录接口报了跨域失败的bug,导致后面清除浏览器缓存的逻辑没有走。需要修改的地方如下

3.1 后端修改代码

WebSecurityConfig类中修改configure(HttpSecurity http)方法

3.2 前端修改代码

修改src/store/modules/user.js文件中的 actions中的 logout行为

代码语言:javascript
复制
 // user logout
  logout({ commit, state, dispatch }) {
    return new Promise((resolve, reject) => {
      if (!window.sessionStorage.getItem('userInfo')) {
        Message.info('用户当前未登录登录')
        resolve()
      } else {
        commit('SET_TOKEN', '')
        commit('SET_ROLES', [])
        commit('SET_NAME', '')
        commit('SET_CURRENT_ROLE', null)
        window.sessionStorage.removeItem('userInfo')
        window.sessionStorage.removeItem('routeIds')
        window.sessionStorage.removeItem('roles')
        window.sessionStorage.removeItem('currentRole')
        removeToken()
        resetRouter()
        // reset visited views and cached views
        // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
        dispatch('tagsView/delAllViews', null, { root: true })
        Message.info('退出登录成功')
        resolve()
      }
    })
  },
  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      commit('SET_TOKEN', '')
      commit('SET_ROLES', [])
      removeToken()
      resolve()
    })
  }

这里作为一种临时的解决方案,没有向后台发送退出登录的请求了。因为笔者发现前端调用退出接口时一直报诡异的跨域失败问题,短时间之内笔者难以解决,先用这种临时方案替换了,等解决了退出接口跨域失败的问题了再来完善修改本文。

4 小结

本文主要完成了给选中用户添加角色和删除角色等功能,同时解决了一个系统退出登录失败和后端接口返回信息提示用户没有登录的情况下没有跳转到登录页面两个Bug。下一篇关于实现自定义授权功能的文章笔者将继续带领大家一起实现角色的增删改查及给角色添加资源权限等功能,敬请期待!

写文不易,诚邀看到这里的朋友都在下方点个再看,谢谢!

本文前端项目gitee地址:

https://gitee.com/heshengfu1211/vue-element-admin.git

后端项目地址:

https://gitee.com/heshengfu1211/blogserver.git

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 阿福谈Web编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1 实现后端接口开发
  • 2 实现前端视图组件与方法逻辑
  • 2.2 用户管理组件添加分配角色对话框并绑定按钮方法
  • 2.3 效果体验
  • 3 解决用户退出登录失败的bug
  • 4 小结
相关产品与服务
访问管理
访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档