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

目录

前言

一、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@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return this.authorities;}public void setAuthorities(List<GrantedAuthority> authorities) {this.authorities = authorities;}// 返回用户密码,上面声明了属性 password@Overridepublic String getPassword() {return password;}// 返回用户名,上面声明了属性 username@Overridepublic String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return accountnonexpired;}public void setAccountnonexpired(boolean accountnonexpired) {this.accountnonexpired = accountnonexpired;}@Overridepublic boolean isAccountNonLocked() {return accountnonlocked;}public void setAccountnonlocked(boolean accountnonlocked) {this.accountnonlocked = accountnonlocked;}@Overridepublic boolean isCredentialsNonExpired() {return credentialsnonexpired;}public void setCredentialsnonexpired(boolean credentialsnonexpired) {this.credentialsnonexpired = credentialsnonexpired;}@Overridepublic 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 dwhere a.id = b.user_id and b.role_id = c.role_id and c.permission_id = d.idand 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 {@Autowiredprivate SystemDao systemDao;@Overridepublic 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.mzph.cn/news/644810.shtml

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

相关文章

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

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

2023春秋杯冬季赛 --- Crypto wp

文章目录 前言Cryptonot_wiener 前言 比赛没打&#xff0c;赛后随便做一下题目 Crypto not_wiener task.py: from Crypto.Util.number import * from gmpy2 import * import random, os from hashlib import sha1 from random import randrange flagb x bytes_to_long(f…

量化交易学习1

一、股票数据基本分类 可分为&#xff08;1&#xff09;技术面数据和&#xff08;2&#xff09;基本面数据 &#xff08;1&#xff09;技术面数据 技术面数据是通过股票的历史价格和交易量等市场数据进行计算和分析得出的指标。常用的技术指标包括移动平均线、相对强弱指标、…

在上海做程序员这么多年,退休后我的工资是多少?

大家好&#xff0c;我是拭心。 最近看到一个很可惜的事&#xff1a;有个阿姨在深圳缴纳了 12 年社保&#xff0c;第 13 年家里突然有事不得不回老家&#xff0c;回去后没再缴纳社保&#xff0c;结果退休后无法领退休工资&#xff0c;还得出来打工赚钱。 之所以这样&#xff0…

重温经典struts1之自定义Filter(拦截器)解决中文乱码问题

重温经典struts1之自定义Filter解决中文乱码问题 前言Filter&#xff08;拦截器&#xff09;需求具体实现步骤1. 自定义CharsetEncodingFilter拦截类2 将自定义CharsetEncodingFilter注册到web.xml3 编写测试用的login页面和处理逻辑 总结 前言 页面输入的中文&#xff0c;Act…

UF_UI_select_with_single_dialog()通过单选对话框选择单个对象。对象可以通过光标或输入名称进行选择。对象被突显出来。

int response0;//返回用户操作类型&#xff0c;点了哪一种返回取消或者确定tag_t objtagNULL_TAG;//输出选择对象tag;double cursor[ 3 ];//输出光标位置tag_t view_tagNULL_TAG;//输出视图tag;UF_UI_select_with_single_dialog("请选择一个对象","获取对象类型…

无人机航迹规划(五):七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划(提供MATLAB代码)

一、七种算法&#xff08;DBO、LO、SWO、COA、LSO、KOA、GRO&#xff09;简介 1、蜣螂优化算法DBO 蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09;由Jiankai Xue和Bo Shen于2022年提出&#xff0c;该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁…

全球先端实验室护肤品牌德妃DERMAFIRM连续6年荣获“韩国第一品牌大奖”

全球先端实验室护肤品牌德妃(DERMAFIRM)在韩国消费者论坛主办的“2024年韩国第一品牌大奖(KOREA FIRST BRAND AWARDS 2024)”中&#xff0c;连续6年获得了由中国消费者评选的实验室护肤品牌部门大奖。 今年迎来第22届的“韩国第一品牌大奖(KOREA FIRST BRAND AWARDS)”是韩国规…

【Go面试向】defer与time.sleep初探

【Go面试向】defer与time.sleep初探 大家好 我是寸铁&#x1f44a; 总结了一篇defer传参与time.sleep初探的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 请大家看下面这段代码&#xff0c;看运行结果会出现什么&#xff0c;为什么&#xff1f; 问题 demo package mainim…

RubbleDB: CPU-Efficient Replication with NVMe-oF——论文泛读

ATC 2023 Paper 论文阅读笔记整理 问题 由于需要执行昂贵的后台压缩操作&#xff0c;CPU 往往是持久键值存储的性能瓶颈。在日志结构合并树&#xff08;LSM树&#xff09;&#xff0c;标准的基于磁盘的键值存储设计[2,4,8,22,41]&#xff0c;压缩可以在生产工作负载中消耗高达…

knife4j调用接口报404

问题 Knife4j文档请求异常&#xff0c;请求资源的接口都是404 解决方法 就是请求路径出错了&#xff0c;我一开始还以为是拦截器拦截了来自knife4j发来的请求。。。

【Godot4自学手册】第四节动画状态机-AnimationTree

各位同学大家好&#xff01;今天继续学习Godot4&#xff0c;本节将要学习AnimationTree&#xff0c;来实现控制主人公的动画。 一、AnimationPlay节点介绍 Godot引擎通过AnimationPlay节点实现了最灵活的动画系统&#xff0c;它几乎可以给godot中的任意节点的任意属性添加动画…

快速上手的AI工具-文心一言辅助学习

前言 大家好晚上好&#xff0c;现在AI技术的发展&#xff0c;它已经渗透到我们生活的各个层面。对于普通人来说&#xff0c;理解并有效利用AI技术不仅能增强个人竞争力&#xff0c;还能在日常生活中带来便利。无论是提高工作效率&#xff0c;还是优化日常任务&#xff0c;AI工…

[完美解决]Vue/React项目运行时出现this[kHandle] = new _Hash(algorithm, xofLen)

问题出现的原因 出现这个问题是node.js 的版本问题&#xff0c;因为 node.js V17开始版本中发布的是OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制&#xff0c;可能会对生态系统造成一些影响。故此以前的项目在使用 nodejs V17以上版本后会报错。而github项目…

macOS磁盘管理工具Paragon Hard Disk Manager,轻松且安全的改变磁盘分区

Paragon Hard Disk Manager mac版是Macos上一款磁盘管理工具&#xff0c;可以帮助你轻松而且安全的随意改变磁盘分区的大小和各种分区参数&#xff0c;作为mac磁盘分区工具也是游刃有余&#xff0c;同时在找回数据的时候也非常容易&#xff0c;并且不会损坏原来的数据&#xff…

Java 序列化

Java 序列化 标记接口transient&#xff08;转瞬即逝的&#xff09;Java 序列化常用 APIserialVersionUIDwriteReplace 序列化机制可以让对象地保存到硬盘上&#xff0c;减轻内存压力的同时&#xff0c;也起了持久化的作用&#xff1b;也可以让 Java 对象在网络传输。一般我们可…

Java多态

多态 什么事多态&#xff1a; 同类型的对象表现出的不同的形态 多态的表现形式&#xff1a; 父类类型 对象名称子类对象&#xff1b; 满足多态的前提&#xff1a; 1.有继承或者实现的关系 2.有父类对象引用指向子类对象 &#xff08;父类 变量名 new 子类&#xff08;&#…

【MySQL索引特性】

文章目录 1. 没有索引&#xff0c;可能会有什么问题2. 认识磁盘2.1 MySQL与存储2.2 先来研究一下磁盘&#xff1a;2.3 磁盘随机访问(Random Access)与连续访问(Sequential Access) 3. MySQL 与磁盘交互基本单位4. 建立共识5. 索引的理解5.1 建立测试表5.2 插入多条记录5.3 查看…

【C++干货铺】C++中的四种类型转换

个人主页点击直达&#xff1a;小白不是程序员 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 C语言中的类型转换 为什么C需要四种类型转化 C强制类型转换 static_cast reinterpret_cast const_cast dynamic_cast RTTI C语言中的类型转换 在C语言中&…

k8s部署Ingress

前提&#xff1a;有自备的域名&#xff0c;没有域名可用主机配置的域名解析代替测试 #主机配置的域名 vi /etc/hosts #追加以下内容 127.0.0.1 kuboard1、部署Ingress vi deploy.yaml #输入以下内容apiVersion: v1 kind: Namespace metadata:labels:app.kubernetes.io/instan…