SpringSecurity认证登录成功后获取角色菜单

news2024/12/24 11:43:03

目录

前言

一、RBAC模型

二、实战应用

1. 建立用户、角色、资源实体类

2. 数据层查询角色资源

3. 业务层实现,调用数据层查询接口

4. SystemController控制器菜单获取方法

5. menu.jsp菜单页面实现


前言

本篇文章接SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/u011529483/article/details/135699004?spm=1001.2014.3001.5501

文章之后,代码在同一个示例工程中。如有必要请参考此文。


一、RBAC模型

本文获取菜单资源是基于角色分配的方式获得的。即什么用户是什么样的角色,什么角色可以访问什么资源。也就是RBAC模型(Role-Based Access Control:基于角色的访问控制)。RBAC模型的3个基础组成部分便是:用户、角色和权限。

  • User(用户):用户有唯一的ID,分配到不同的角色上
  • Role(角色):角色有唯一的ID,角色分配有不同的权限(资源)
  • Permission(权限):资源有唯一的ID,系统的访问权限(资源)
  • 用户-角色映射:用户和角色建立对应关系。用户表ID对应角色表ID
  • 角色-权限映射:角色和权限(资源)建立对应关系。角色表ID对应资源表ID

二、实战应用

1. 建立用户、角色、资源实体类

package com.wqbr.domain;


import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 系统用户,封装用户数据,实现 UserDetails 接口
 * @author lv
 * @date 2024年1月11日
 */
public class SysUser implements UserDetails {

  private static final long serialVersionUID = 1L;

  private String id;
  private String username; //从UserDetails的重写方法中返回
  private String password; //从UserDetails的重写方法中返回
  private Date addtime;
  private boolean accountnonexpired; //账户是否过期,从UserDetails的重写方法中返回
  private boolean accountnonlocked; //账户是否锁定,从UserDetails的重写方法中返回
  private boolean credentialsnonexpired; //密码是否过期,从UserDetails的重写方法中返回
  private boolean enabled; //账户是否可用,从UserDetails的重写方法中返回

  // 储存用户拥有的所有权限
  private List<GrantedAuthority> authorities = new ArrayList<>(); //从UserDetails的重写方法中返回


  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public Date getAddtime() {
    return addtime;
  }

  public void setAddtime(Date addtime) {
    this.addtime = addtime;
  }

  // 返回用户权限,上面声明了权限集合对象 authorities
  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    return this.authorities;
  }

  public void setAuthorities(List<GrantedAuthority> authorities) {
    this.authorities = authorities;
  }

  // 返回用户密码,上面声明了属性 password
  @Override
  public String getPassword() {
    return password;
  }

  // 返回用户名,上面声明了属性 username
  @Override
  public String getUsername() {
    return username;
  }

  @Override
  public boolean isAccountNonExpired() {
    return accountnonexpired;
  }

  public void setAccountnonexpired(boolean accountnonexpired) {
    this.accountnonexpired = accountnonexpired;
  }

  @Override
  public boolean isAccountNonLocked() {
    return accountnonlocked;
  }

  public void setAccountnonlocked(boolean accountnonlocked) {
    this.accountnonlocked = accountnonlocked;
  }

  @Override
  public boolean isCredentialsNonExpired() {
    return credentialsnonexpired;
  }

  public void setCredentialsnonexpired(boolean credentialsnonexpired) {
    this.credentialsnonexpired = credentialsnonexpired;
  }

  @Override
  public boolean isEnabled() {
    return enabled;
  }

  public void setEnabled(boolean enabled) {
    this.enabled = enabled;
  }
}
package com.wqbr.domain;

/**
 * 系统角色
 * @author lv
 * @date 2024年1月16日
 */
public class SysRole {

  private String id;
  private String available;
  private String description;
  private String role;


  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }


  public String getAvailable() {
    return available;
  }

  public void setAvailable(String available) {
    this.available = available;
  }


  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }


  public String getRole() {
    return role;
  }

  public void setRole(String role) {
    this.role = role;
  }

}
package com.wqbr.domain;

/**
 * 系统资源
 * @author lv
 * @date 2024年1月16日
 */
public class SysPermission {

  private String id;
  private String available;
  private String name;
  private String parent_id;
  private String parent_ids;
  private String permission;
  private String resource_type;
  private String url;


  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }


  public String getAvailable() {
    return available;
  }

  public void setAvailable(String available) {
    this.available = available;
  }


  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }


  public String getParent_id() {
    return parent_id;
  }

  public void setParent_id(String parent_id) {
    this.parent_id = parent_id;
  }

  public String getParent_ids() {
    return parent_ids;
  }

  public void setParent_ids(String parent_ids) {
    this.parent_ids = parent_ids;
  }

  public String getPermission() {
    return permission;
  }

  public void setPermission(String permission) {
    this.permission = permission;
  }


  public String getResource_type() {
    return resource_type;
  }

  public void setResource_type(String resource_type) {
    this.resource_type = resource_type;
  }

  public String getUrl() {
    return url;
  }

  public void setUrl(String url) {
    this.url = url;
  }

}

关于这3个表的建表语句,数据插入语句请参考此文(数据库oracle)spirng框架之spring security(二)insert 语句补充-CSDN博客

2. 数据层查询角色资源

定义SystemDao接口类的查询方法

    /**
     * 查询当前用户拥有的资源
     */
    public List<SysPermission> findPermissionByUsername(String username);

SystemDao.xml(mybatis的mapper文件)查询语句

    <!--查询当前用户拥有的资源-->
    <select id="findPermissionByUsername" parameterType="String" resultType="com.wqbr.domain.SysPermission">
        select d.*
        from sys_user a, sys_user_role b, sys_role_permission c, sys_permission d
        where a.id = b.user_id and b.role_id = c.role_id and c.permission_id = d.id
          and a.username = #{username}
    </select>

3. 业务层实现,调用数据层查询接口

package com.wqbr.service;

import com.wqbr.domain.SysPermission;

import java.util.List;

/**
 * 系统服务接口
 * @author lv
 * @date 2024年1月11日
 */
public interface SystemService {
    /**
     * 查询当前用户拥有的资源
     */
    public List<SysPermission> findPermissionByUsername(String username);
}
package com.wqbr.service.impl;

import com.wqbr.domain.SysPermission;
import com.wqbr.persistence.SystemDao;
import com.wqbr.service.SystemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


/**
 * 系统服务接口实现
 * @author lv
 * @date 2024年1月11日
 */
@Service
public class SystemServiceImpl implements SystemService {

    @Autowired
    private SystemDao systemDao;

    @Override
    public List<SysPermission> findPermissionByUsername(String username) {
        return systemDao.findPermissionByUsername(username);
    }
}

4. SystemController控制器菜单获取方法

先新建一个菜单数据装载实体类Menus

package com.wqbr.domain;

/**
 * 定义的实体类,保存菜单数据
 */
public class Menus {
    private long id;
    private String name;
    private Long parentId;
    private Long parentIds;
    private String url;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getParentId() {
        return parentId;
    }

    public void setParentId(Long parentId) {
        this.parentId = parentId;
    }

    public Long getParentIds() {
        return parentIds;
    }

    public void setParentIds(Long parentIds) {
        this.parentIds = parentIds;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

SystemController类中的方法

    @GetMapping("/findMenu")
    public ModelAndView findMenus(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
        ModelAndView model = new ModelAndView("main/menu");
        SysUser user = (SysUser) authentication.getPrincipal();
        String username=user.getUsername();
        if(username!=null){
            List<Menus> listMenu = new ArrayList<>();
            List<SysPermission> pList = systemService.findPermissionByUsername(username);
            System.out.println("=-----=大小为:"+pList.size());
            for (SysPermission permission : pList) {
                if (permission.getResource_type().equals("menu")) {
                    Menus menu = new Menus();
                    menu.setId(Long.parseLong(permission.getId()));
                    menu.setName(permission.getName());
                    menu.setParentId(Long.parseLong(permission.getParent_id()));
                    menu.setParentIds(Long.parseLong(permission.getParent_ids()));
                    menu.setUrl(permission.getUrl());
                    listMenu.add(menu);
                }
            }
            //request.setAttribute("listMenus", listMenu);
            model.addObject("listMenu",listMenu);

//            for (Menus menus : listMenu) {
//                if (menus.getParentId() == 10000) { //10000为数据库中的值
//                    System.out.println("==" + menus.getName() + "[" + menus.getUrl() + "]");
//                    for (Menus menusch : listMenu) {
//                        if (menus.getId() == menusch.getParentId()) {
//                            System.out.println("---------" + menusch.getName() + "[" + menusch.getUrl() + "]");
//                        }
//                    }
//                }
//            }
        }
        return model;
    }

到此已经可以运行项目,登录成功后在浏览器地址栏调用控制器的 /findMenu 请求在控制台打印出菜单结构。

5. menu.jsp菜单页面实现

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<html>
<head>
    <title>菜单列表</title>
</head>
<body>
<div><h2>导航菜单</h2></div>
<!-- 菜单开始 -->
<div>
    <h4>列表大小:${listMenu.size()}</h4>
    <c:choose>
        <c:when test="${listMenu.size()>0}">
            <dl>
                <c:forEach var="lstMenu" items="${listMenu}" varStatus="status">
                    <c:if test="${lstMenu.parentId eq 10000}">
                        <dt style="height: 28px;">
                            <span>■</span>
                            <span onclick="alert('■父菜单${status.index}')">${lstMenu.name}</span>:
                            <span>${lstMenu.url}</span>
                        </dt>
                        <c:forEach var="menuChild" items="${listMenu}">
                            <c:if test="${menuChild.parentId eq lstMenu.id}">
                                <dd style="height: 25px;">
                                    <span>●</span>
                                    <span onclick="alert('●子菜单${status.index}')">${menuChild.name}</span>:
                                    <span>${menuChild.url}</span>
                                </dd>
                            </c:if>
                        </c:forEach>
                    </c:if>
                </c:forEach>
            </dl>
        </c:when>
        <c:otherwise>
            <p>没有查询到菜单列表!</p>
        </c:otherwise>
    </c:choose>
</div>
<!-- 菜单结束 -->
</body>
</html>

菜单页面实现结束,现在运行项目查看页面效果。

登录成功后浏览器输入:http://localhost:8080/wqdemotwo_war/system/findMenu

用户表中有两个用户:

zhangsan用户登录成功后的菜单资源:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1406840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

捆扎打包机的选择使用以及维修

捆包机又称打包机或捆扎机&#xff0c;是使用捆扎带缠绕产品或包装件&#xff0c;然后收紧并将两端通过热效应熔融或使用包扣等材料连接的机器。捆包机的功用是使塑料带能紧贴于被捆扎包件表面&#xff0c;保证包件在运输、贮存中不因捆扎不牢而散落&#xff0c;同时还使捆扎整…

MySQL也开始支持JavaScript了

2023 年 12 月 16 日&#xff0c;Oracle 公司在一篇名为 《Introducing JavaScript support in MySQL》的文章中宣布 MySQL 数据库服务器将开始支持 JavaScript 语言。 这个举措标志着继PostgreSQL之后&#xff0c; MySQL 也支持使用 JavaScript 编写函数和存储过程了。作为最…

SQL注入示例

例一、基础SQL注入&#xff1a;load_file读文件 CISP-PTE 认证考试 首先是有单引号和括号的&#xff0c;首要是要闭合&#xff0c;然后回显点是在-1的位置&#xff0c;读取文件上面的key的话使用的是load_file(/tmp/360/key) id-1)%09ununionion%09select%091,2,3,load_file…

NineData支持制定安全、可靠的SQL开发规范

在和数据库打交道中&#xff0c;不管是数据库管理员&#xff08;DBA&#xff09;还是开发人员&#xff0c;经常会做一些CURD操作。因为每个人对数据库的了解程度不一样&#xff0c;所以在项目上线时&#xff0c;往往还需要专职人员对数据库的CURD操作进行审核&#xff0c;确保C…

FPGA硬件架构——具体型号是xc7k325tffg676-2为例

1.共如下图14个时钟域&#xff0c;XmYn(按坐标理解) 2.IOB(IOB为可编程输入输出单元,当然在普通Bank上的IOB附近还有很多时钟资源&#xff0c;例如PLL&#xff0c;MMCM资源。), 2.1 FPGA的Bank分为HP Bank和HR Bank&#xff0c;二者对电压的要求范围不同&#xff0c;HR支持更大…

亚信安慧AntDB:AntDB-M元数据锁之对象锁(四)

l 对象锁 (per-object locks) 除了IX锁&#xff0c;其他类型都可以用于其他命名空间&#xff0c;这部分是最常用的锁类型。主要用于对数据库的某个具体元数据的并发控制。这类锁对象会比较多&#xff0c;对其有独特的管理&#xff0c;本文不再展开说明。 5.3 两种锁类型 根据…

【Java程序员面试专栏 专业技能篇】计算机网络核心面试指引

关于计算机网络部分的核心知识进行一网打尽,包括计算机的网络模型,各个层的一些重点概念,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 分层基本概念 计算机网络模型的分层及具体作用 计算机网络有哪些分层模型 可以按照应用层到物…

vivado:关联notepad++

网上好多都要下插件&#xff0c;看了野火视频&#xff0c;直接在vivado里面加路径弄好的 2 3&#xff08;那个fonts and colors也经常用 改字体&#xff09; 4 5 以下是我的路径 D:/gongjuruanjian/notepad/Notepad/notepad.exe [file name] -n[line number] 把[file name] -…

网关配置快速入门

网关配置快速入门 前端请求统一发送到网关&#xff1a; window.SITE_CONFIG[baseUrl] http://localhost:8088/api;网关服务中配置路由转发&#xff1a; server:port: 8088spring:application:name: gulimall-gateway #服务名称config:import: nacos:bootstrap.yaml #引入…

NAT配置

目录 静态NAT配置配置抓包测试 动态NAT配置配置测试 Easy IP配置配置测试 静态NAT配置 配置 nat static global { global-address} inside {host-address } 命令用于创建静态NAT。 global参数用于配置外部公网地址。 inside参数用于配置内部私有地址。 AR1-NAT <Huawei&g…

新版idea创建spring boot项目

目录 前言 汉化教程 项目模板初始化 1.点击新建项目 2.配置初始化信息 3.初始依赖选择 配置Maven 1.打开maven设置 2.重写maven配置文件 3.选择你创建的配置文件 4.重启项目 spring boot配置并测试 1.修改配置文件后缀 2.启动项目 3.编写测试控制类 4.重启项目…

【深度学习:Collaborative filtering 协同过滤】深入了解协同过滤:技术、应用与示例

此图显示了使用协作筛选预测用户评分的示例。起初&#xff0c;人们会对不同的项目&#xff08;如视频、图像、游戏&#xff09;进行评分。之后&#xff0c;系统将对用户对项目进行评分的预测&#xff0c;而用户尚未评分。这些预测基于其他用户的现有评级&#xff0c;这些用户与…

rsync数据同步和sersync数据实时同步服务器

rsync数据同步和sersync数据实时同步服务器 基于三台服务器&#xff0c;部署数据实时同步服务器&#xff0c;一台作为主服务器sersync&#xff08;推送数据&#xff09;&#xff0c;其余两台作为备用服务器rsync&#xff08;拉取数据&#xff09;。 rsync 数据同步 环境&am…

2月重要外贸节日,可以开始计划营销了

快过年了&#xff0c;外贸小伙伴们终于可以好好休息了。享受2月春节假期的同时&#xff0c;咱们也别忘了客户所在国的节日&#xff0c;在国庆日、纪念日等重要日子&#xff0c;给客户们送上祝福。 2月4日 斯里兰卡-国庆日 National Day 斯里兰卡历史悠久&#xff0c;公元前4…

后台管理系统更新

菜单列表代码&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>菜单列表</title> <meta http-equiv"X-UA-Compatible" content"IEedge,chrome1"> <me…

Python的type()函数

在Python中&#xff0c;type()函数是一个非常有用的工具&#xff0c;它可以查看变量或对象的数据类型。了解如何使用type()函数对于编写高质量的Python代码非常重要&#xff0c;因为它有助于确保程序按预期运行&#xff0c;避免潜在的错误和异常。本文将深入探讨type()函数的用…

【ZYNQ入门】第九篇、双帧缓存的原理

目录 第一部分、基础知识 1、HDMI视频撕裂的原理 2、双帧缓存的原理 第二部分、代码设计原理 1、AXI_HP_WR模块 2、AXI_HP_RD模块 3、Block design设计 第三部分、总结 1、写在最后 2、更多文章 第一部分、基础知识 1、HDMI视频撕裂的原理 在调试摄像头的时候&#xf…

IMS 中的Implicit Registration

IMS Implicit Registration在23.228中有描述,在23.228中搜索关键字“Implicit Registration”直达,简单看下: 当用户具有一个public user ID set,通过该set 中的某个public user ID 进行单个IMS注册来Implicit Registration的public user ID时,它被视为Implicit Registrat…

npm或者pnpm或者yarn安装依赖报错ENOTFOUND解决办法

如果报错说安装依赖报错&#xff0c;大概率是因为npm源没有设置对&#xff0c;比如我这里安装protobufjs的时候报错&#xff1a;ENOTFOUND npm ERR! code ENOTFOUND npm ERR! syscall getaddrinfo npm ERR! errno ENOTFOUND npm ERR! network request to https://registry.cnpm…

时隔78天,个人微信小游戏内容审核终于通过了,这到底是经历了什么...

引言 大家好&#xff0c;就在前天&#xff0c;笔者惊讶地发现&#xff0c;去年提交的微信小游戏内容审核居然过审了&#xff01; 我们一起来看一下笔者都经历了什么&#xff1f; 以及了解下微信小游戏备案的具体流程是怎么样的&#xff1f; 回顾一下 先回顾一下&#xff0c…