<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Security 實(shí)現(xiàn)動(dòng)態(tài)權(quán)限菜單方案(附源碼)

          共 34295字,需瀏覽 69分鐘

           ·

          2022-07-08 21:31

          ????關(guān)注后回復(fù) “進(jìn)群” ,拉你進(jìn)程序員交流群????

          系統(tǒng)權(quán)限管理

          1、前言

          在實(shí)際開發(fā)中,開發(fā)任何一套系統(tǒng),基本都少不了權(quán)限管理這一塊。這些足以說明權(quán)限管理的重要性。其實(shí)SpringSecurity去年就學(xué)了,一直沒有時(shí)間整理,用了一年多時(shí)間了,給我的印象一直都挺好,實(shí)用,安全性高(Security可以對(duì)密碼進(jìn)行加密)。而且這一塊在實(shí)際開發(fā)中也的確很重要,所以這里整理了一套基于SpringSecurity的權(quán)限管理。

          案例代碼下面有下載鏈接。

          2、案例技術(shù)棧

          如果對(duì)于SpringSecurity還不了解的話可以先了解一下SpringSecurity安全控件的學(xué)習(xí),頁面采用的是Bootstrap寫的(頁面就簡(jiǎn)單的寫了一下,可以根據(jù)自己的需求更改),其實(shí)后端理解了,前臺(tái)就是顯示作用,大家可以自行更換前臺(tái)頁面顯示框架,持久層使用的是Spring-Data-Jpa。

          并且對(duì)后端持久層和控制器進(jìn)行了一下小封裝,Java持久層和控制器的封裝。頁面使用的Thymeleaf模板,SpringBoot整合Thymeleaf模板。

          數(shù)據(jù)庫設(shè)計(jì)

          1、表關(guān)系

          • 菜單(TbMenu)=====> 頁面上需要顯示的所有菜單

          • 角色(SysRole)=====> 角色及角色對(duì)應(yīng)的菜單

          • 用戶(SysUser)=====> 用戶及用戶對(duì)應(yīng)的角色

          • 用戶和角色中間表(sys_user_role)====> 用戶和角色中間表

          2、數(shù)據(jù)庫表結(jié)構(gòu)

          菜單表tb_menu

          角色及菜單權(quán)限表sys_role,其中父節(jié)點(diǎn)parent 為null時(shí)為角色,不為null時(shí)為對(duì)應(yīng)角色的菜單權(quán)限。

          用戶表sys_user

          用戶和角色多對(duì)多關(guān)系,用戶和角色中間表sys_user_role(有Spring-Data-Jpa自動(dòng)生成)。

          新建項(xiàng)目

          1、新建springboot項(xiàng)目

          新建springboot項(xiàng)目,在項(xiàng)目中添加SpringSecurity相關(guān)Maven依賴,pom.map文件

          <?xml version="1.0" encoding="UTF-8"?>
          <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

              <modelVersion>4.0.0</modelVersion>
              <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-parent</artifactId>
                  <version>2.2.2.RELEASE</version>
                  <relativePath/> <!-- lookup parent from repository -->
              </parent>
              <groupId>com.mcy</groupId>
              <artifactId>springboot-security</artifactId>
              <version>0.0.1-SNAPSHOT</version>
              <name>springboot-security</name>
              <description>Demo project for Spring Boot</description>
           
              <properties>
                  <java.version>1.8</java.version>
              </properties>
           
              <dependencies>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-data-jpa</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-security</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-thymeleaf</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-web</artifactId>
                  </dependency>
           
                  <dependency>
                      <groupId>mysql</groupId>
                      <artifactId>mysql-connector-java</artifactId>
                      <scope>runtime</scope>
                  </dependency>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-test</artifactId>
                      <scope>test</scope>
                      <exclusions>
                          <exclusion>
                              <groupId>org.junit.vintage</groupId>
                              <artifactId>junit-vintage-engine</artifactId>
                          </exclusion>
                      </exclusions>
                  </dependency>
                  <dependency>
                      <groupId>org.springframework.security</groupId>
                      <artifactId>spring-security-test</artifactId>
                      <scope>test</scope>
                  </dependency>
                  <dependency>
                      <groupId>org.thymeleaf.extras</groupId>
                      <artifactId>thymeleaf-extras-springsecurity5</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-devtools</artifactId>
                      <scope>runtime</scope>
                      <optional>true</optional>
                  </dependency>
                  <dependency>
                      <groupId>org.webjars.bower</groupId>
                      <artifactId>bootstrap-select</artifactId>
                      <version>2.0.0-beta1</version>
                  </dependency>
                  <dependency>
                      <groupId>org.webjars</groupId>
                      <artifactId>bootbox</artifactId>
                      <version>4.4.0</version>
                  </dependency>
              </dependencies>
           
              <build>
                  <plugins>
                      <plugin>
                          <groupId>org.springframework.boot</groupId>
                          <artifactId>spring-boot-maven-plugin</artifactId>
                      </plugin>
                  </plugins>
              </build>
           
          </project>

          2、項(xiàng)目結(jié)構(gòu)

          編寫代碼

          1、編寫實(shí)體類

          菜單表實(shí)體類TbMenu,Spring-Data-Jpa可以根據(jù)實(shí)體類去數(shù)據(jù)庫新建或更新對(duì)應(yīng)的表結(jié)構(gòu),詳情可以訪問Spring-Data-Jpa入門:

          https://blog.csdn.net/qq_40205116/article/details/103039936

          import com.fasterxml.jackson.annotation.JsonIgnore;
          import com.mcy.springbootsecurity.custom.BaseEntity;
          import org.springframework.data.annotation.CreatedBy;
           
          import javax.persistence.*;
          import java.util.ArrayList;
          import java.util.List;
           
          /**
           * 菜單表
           * @author
           *
           */

          @Entity
          public class TbMenu extends BaseEntity<Integer{
           private String name;
           private String url;
           private Integer idx;
           @JsonIgnore
           private TbMenu parent;
           @JsonIgnore
           private List<TbMenu> children=new ArrayList<>();
           
           @Column(unique=true)
           public String getName() {
            return name;
           }
           
           public void setName(String name) {
            this.name = name;
           }
           
           public String getUrl() {
            return url;
           }
           
           public void setUrl(String url) {
            this.url = url;
           }
           
           public Integer getIdx() {
            return idx;
           }
           
           public void setIdx(Integer idx) {
            this.idx = idx;
           }
           
           @ManyToOne
           @CreatedBy
           public TbMenu getParent() {
            return parent;
           }
           
           public void setParent(TbMenu parent) {
            this.parent = parent;
           }
           
           @OneToMany(cascade=CascadeType.ALL,mappedBy="parent")
           @OrderBy(value="idx")
           public List<TbMenu> getChildren() {
            return children;
           }
           
           public void setChildren(List<TbMenu> children) {
            this.children = children;
           }
           
           public TbMenu(Integer id) {
            super(id);
           }
           
           public TbMenu(){
            super();
           }
           
           public TbMenu(String name, String url, Integer idx, TbMenu parent, List<TbMenu> children) {
            this.name = name;
            this.url = url;
            this.idx = idx;
            this.parent = parent;
            this.children = children;
           }
           
           public TbMenu(Integer integer, String name, String url, Integer idx, TbMenu parent, List<TbMenu> children) {
            super(integer);
            this.name = name;
            this.url = url;
            this.idx = idx;
            this.parent = parent;
            this.children = children;
           }
           
           @Transient
           public Integer getParentId() {
            return parent==null?null:parent.getId();
           }
          }

          表新建好了,下面就是實(shí)現(xiàn)增刪改查就可以了,實(shí)現(xiàn)效果如下。

          新增和修改菜單。

          對(duì)于Bootstrap的樹形表格,可以移步到:BootStrap-bable-treegrid樹形表格的使用。

          https://blog.csdn.net/qq_40205116/article/details/103740104

          菜單管理實(shí)現(xiàn)了,下一步就是實(shí)現(xiàn)角色及角色對(duì)應(yīng)的權(quán)限管理了。

          角色及權(quán)限表SysRole,parent 為null時(shí)為角色,不為null時(shí)為權(quán)限。

          package com.mcy.springbootsecurity.entity;
           
          import com.fasterxml.jackson.annotation.JsonIgnore;
          import com.mcy.springbootsecurity.custom.BaseEntity;
          import org.springframework.data.annotation.CreatedBy;
          import javax.persistence.*;
          import java.util.ArrayList;
          import java.util.List;
           
          @Entity
          /***
           * 角色及角色對(duì)應(yīng)的菜單權(quán)限
           * @author
           *parent 為null時(shí)為角色,不為null時(shí)為權(quán)限
           */

          public class SysRole extends BaseEntity<Integer{
           private String name; //名稱
           private String code; //代碼
           @JsonIgnore
           private SysRole parent;
           private Integer idx; //排序
           @JsonIgnore
           private List<SysRole> children = new ArrayList<>();
           
           @Column(length=20)
           public String getName() {
            return name;
           }
           
           public void setName(String name) {
            this.name = name;
           }
           
           public String getCode() {
            return code;
           }
           
           public void setCode(String code) {
            this.code = code;
           }
           
           @ManyToOne
           @CreatedBy
           public SysRole getParent() {
            return parent;
           }
           
           public void setParent(SysRole parent) {
            this.parent = parent;
           }
           
           @OneToMany(cascade=CascadeType.ALL,mappedBy="parent")
           public List<SysRole> getChildren() {
            return children;
           }
           
           public void setChildren(List<SysRole> children) {
            this.children = children;
           }
           
           //獲取父節(jié)點(diǎn)id
           @Transient
           public Integer getParentId() {
            return parent==null?null:parent.getId();
           }
           
           public Integer getIdx() {
            return idx;
           }
           
           public void setIdx(Integer idx) {
            this.idx = idx;
           }
           
           public SysRole(String name, String code, SysRole parent, Integer idx, List<SysRole> children) {
            this.name = name;
            this.code = code;
            this.parent = parent;
            this.idx = idx;
            this.children = children;
           }
           
           public SysRole(Integer id, String name, String code, SysRole parent, Integer idx, List<SysRole> children) {
            super(id);
            this.name = name;
            this.code = code;
            this.parent = parent;
            this.idx = idx;
            this.children = children;
           }
           
           public SysRole(Integer id) {
            super(id);
           }
           
           public SysRole(){}
          }

          首先需要實(shí)現(xiàn)角色管理,之后在角色中添加對(duì)應(yīng)的菜單權(quán)限。

          實(shí)現(xiàn)效果(也可以和菜單管理一樣,用樹形表格展示,根據(jù)個(gè)人需求。這里用的是樹形菜單展示的)。

          給角色分配權(quán)限。

          最后實(shí)現(xiàn)的就是用戶管理了,只需要對(duì)添加的用戶分配對(duì)應(yīng)的角色就可以了,用戶登錄時(shí),顯示角色對(duì)應(yīng)的權(quán)限。

          用戶表SysUser,繼承的BaseEntity類中就一個(gè)ID字段。

          import com.fasterxml.jackson.annotation.JsonIgnore;
          import com.mcy.springbootsecurity.custom.BaseEntity;
           
          import javax.persistence.*;
          import java.util.ArrayList;
          import java.util.List;
           
          /**
           * 用戶表
           */

          @Entity
          public class SysUser extends BaseEntity<Integer{
           private String username; //賬號(hào)
           private String password; //密碼
           private String name;  //姓名
           private String address;  //地址
           
           @JsonIgnore
           private List<SysRole> roles=new ArrayList<>(); //角色
           
           @Column(length=20,unique=true)
           public String getUsername() {
            return username;
           }
           public void setUsername(String username) {
            this.username = username;
           }
           
           @Column(length=100)
           public String getPassword() {
            return password;
           }
           public void setPassword(String password) {
            this.password = password;
           }
           
           @Column(length=20)
           public String getName() {
            return name;
           }
           public void setName(String name) {
            this.name = name;
           }
           
           @ManyToMany(cascade=CascadeType.REFRESH,fetch=FetchType.EAGER)
           @JoinTable(name="sys_user_role",joinColumns=@JoinColumn(name="user_id"),inverseJoinColumns=@JoinColumn(name="role_id"))
           public List<SysRole> getRoles() {
            return roles;
           }
           public void setRoles(List<SysRole> roles) {
            this.roles = roles;
           }
           
           public String getAddress() {
            return address;
           }
           
           public void setAddress(String address) {
            this.address = address;
           }
           
           //角色名稱
           @Transient
           public String getRoleNames() {
            String str="";
            for (SysRole role : getRoles()) {
             str+=role.getName()+",";
            }
            if(str.length()>0) {
             str=str.substring(0, str.length()-1);
            }
            return str;
           }
           
           //角色代碼
           @Transient
           public String getRoleCodes() {
            String str="";
            for (SysRole role : getRoles()) {
             str+=role.getCode()+",";
            }
            if(str.indexOf(",")>0) {
             str=str.substring(0,str.length()-1);
            }
            return str;
           }
           
          }

          用戶管理就基本的數(shù)據(jù)表格,效果如圖。

          2、Security配置文件

          Security相關(guān)配置文件,下面兩個(gè)文件如果看不懂,可以訪問SpringSecurity安全控件的學(xué)習(xí)中有詳細(xì)講解。

          https://blog.csdn.net/qq_40205116/article/details/103439326

          package com.mcy.springbootsecurity.security;
           
          import com.mcy.springbootsecurity.service.SysUserService;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.context.annotation.Configuration;
          import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
          import org.springframework.security.config.annotation.web.builders.HttpSecurity;
          import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
          import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
           
          @Configuration
          public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
           
              @Autowired
              private SysUserService userService;
           
              /**
               * 用戶認(rèn)證操作
               * @param auth
               * @throws Exception
               */

              @Override
              protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                  //添加用戶,并給予權(quán)限
                  auth.inMemoryAuthentication().withUser("aaa").password("{noop}1234").roles("DIY");
                  //設(shè)置認(rèn)證方式
                  auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
              }
           
              /**
               * 用戶授權(quán)操作
               * @param http
               * @throws Exception
               */

              @Override
              protected void configure(HttpSecurity http) throws Exception {
                  http.csrf().disable();    //安全器令牌
                  http.formLogin()
                          //登錄請(qǐng)求被攔截
                          .loginPage("/login").permitAll()
                          //設(shè)置默認(rèn)登錄成功跳轉(zhuǎn)頁面
                          .successForwardUrl("/main")
                          .failureUrl("/login?error");   //登錄失敗的頁面
                  http.authorizeRequests().antMatchers("/static/**""/assets/**").permitAll();    //文件下的所有都能訪問
                  http.authorizeRequests().antMatchers("/webjars/**").permitAll();
                  http.logout().logoutUrl("/logout").permitAll();     //退出
                  http.authorizeRequests().anyRequest().authenticated();    //除此之外的都必須通過請(qǐng)求驗(yàn)證才能訪問
              }
          }

          獲取登錄者相關(guān)信息,工具類。

          import com.mcy.springbootsecurity.entity.SysUser;
          import com.mcy.springbootsecurity.service.SysUserService;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.security.core.GrantedAuthority;
          import org.springframework.security.core.context.SecurityContextHolder;
          import org.springframework.security.core.userdetails.UserDetails;
          import org.springframework.stereotype.Component;
           
          import java.util.ArrayList;
          import java.util.List;
           
          //創(chuàng)建會(huì)話,獲取當(dāng)前登錄對(duì)象
          @Component
          public class UserUtils {
           @Autowired
           private SysUserService userService;
           
           /**
            * 獲取當(dāng)前登錄者的信息
            * @return 當(dāng)前者信息
            */

           public SysUser getUser() {
            //獲取當(dāng)前用戶的用戶名
            String username = SecurityContextHolder.getContext().getAuthentication().getName();
            SysUser user = userService.findByUsername(username);
            return user;
           }
           
           /**
            * 判斷此用戶中是否包含roleName菜單權(quán)限
            * @param roleName
            * @return
            */

           public Boolean hasRole(String roleName) {
            //獲取UserDetails類,
            UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            List<String> roleCodes=new ArrayList<>();
            for (GrantedAuthority authority : userDetails.getAuthorities()) {
             //getAuthority()返回用戶對(duì)應(yīng)的菜單權(quán)限
             roleCodes.add(authority.getAuthority());
            }
            return roleCodes.contains(roleName);
           }
          }

          3、動(dòng)態(tài)權(quán)限菜單加載相關(guān)方法

          用戶表的SysUserService需要實(shí)現(xiàn)UserDetailsService接口,因?yàn)樵赟pringSecurity中配置的相關(guān)參數(shù)需要是UserDetailsService類的數(shù)據(jù)。

          重寫UserDetailsService接口中的loadUserByUsername方法,通過該方法查詢對(duì)應(yīng)的用戶,返回對(duì)象UserDetails是SpringSecurity的一個(gè)核心接口。其中定義了一些可以獲取用戶名,密碼,權(quán)限等與認(rèn)證相關(guān)信息的方法。

          重寫的loadUserByUsername方法。

          @Override
          public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
              //調(diào)用持久層接口findByUsername方法查詢用戶。
              SysUser user = userRepository.findByUsername(username);
              if(user == null){
                  throw new UsernameNotFoundException("用戶名不存在");
              }
              //創(chuàng)建List集合,用來保存用戶菜單權(quán)限,GrantedAuthority對(duì)象代表賦予當(dāng)前用戶的權(quán)限
              List<GrantedAuthority> authorities = new ArrayList<>();
              //獲得當(dāng)前用戶角色集合
              List<SysRole> roles = user.getRoles();
              List<SysRole> haveRoles=new ArrayList<>();
              for (SysRole role : roles) {
                  haveRoles.add(role);
                  List<SysRole> children = roleService.findByParent(role);
                  children.removeAll(haveRoles);
                  haveRoles.addAll(children);
              }
              for(SysRole role: haveRoles){
                  //將關(guān)聯(lián)對(duì)象role的name屬性保存為用戶的認(rèn)證權(quán)限
                  authorities.add(new SimpleGrantedAuthority(role.getName()));
              }
              //此處返回的是org.springframework.security.core.userdetails.User類,該類是SpringSecurity內(nèi)部的實(shí)現(xiàn)
              //org.springframework.security.core.userdetails.User類實(shí)現(xiàn)了UserDetails接口
              return new User(user.getUsername(), user.getPassword(), authorities);
          }

          所有功能實(shí)現(xiàn)了,最后就是根據(jù)角色去顯示對(duì)應(yīng)的菜單了。

          TbMenuService類中的findAuditMenu方法,查詢當(dāng)前用戶所擁有的權(quán)限菜單。

          /**
           * 獲取用戶所擁有的權(quán)限對(duì)應(yīng)的菜單項(xiàng)
           * @return
           */

          public List<TbMenu> findAuditMenu() {
              List<TbMenu> menus;
              //判斷是否是后門用戶
              if(userUtils.hasRole("ROLE_DIY")){
                  //查詢所有菜單,子菜單可以通過父級(jí)菜單的映射得到
                  menus = menuRepository.findByParentIsNullOrderByIdx();
              }else{
                  //獲取此用戶對(duì)應(yīng)的菜單權(quán)限
                  menus = auditMenu(menuRepository.findByParentIsNullOrderByIdx());
              }
              return menus;
          }
           
          //根據(jù)用戶的菜單權(quán)限對(duì)菜單進(jìn)行過濾
          private List<TbMenu> auditMenu(List<TbMenu> menus) {
              List<TbMenu> list = new ArrayList<>();
              for(TbMenu menu: menus){
                  String name = menu.getName();
                  //判斷此用戶是否有此菜單權(quán)限
                  if(userUtils.hasRole(name)){
                      list.add(menu);
                      //遞歸判斷子菜單
                      if(menu.getChildren() != null && !menu.getChildren().isEmpty()) {
                          menu.setChildren(auditMenu(menu.getChildren()));
                      }
                  }
              }
              return list;
          }

          在UserUtils工具類中的hasRole方法,判斷此用戶中是否包含roleName菜單權(quán)限。

          public Boolean hasRole(String roleName) {
           //獲取UserDetails類,
           UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
           List<String> roleCodes=new ArrayList<>();
           for (GrantedAuthority authority : userDetails.getAuthorities()) {
            //getAuthority()返回用戶對(duì)應(yīng)的菜單權(quán)限
            roleCodes.add(authority.getAuthority());
           }
           return roleCodes.contains(roleName);
          }

          之后在控制器中返回用戶對(duì)應(yīng)的菜單權(quán)限,之后在前臺(tái)頁面遍歷就可以了。

          @RequestMapping(value = "/main")
          public String main(ModelMap map){
              //加載菜單
              List<TbMenu> menus = menuService.findAuditMenu();
              map.put("menus", menus);
              if (menus.isEmpty()) {
                  return "main/main";
              }
              return "main/main1";
          }

          4、首頁菜單遍歷

          首頁菜單遍歷,這里使用的是LayUI菜單,如果其他框架可以自行根據(jù)頁面標(biāo)簽規(guī)律遍歷,因?yàn)轫撁媸褂玫氖荰hymeleaf模板,不是JSP,使用遍歷菜單時(shí)不是采用的EL表達(dá)式,而是使用的Thymeleaf自帶的標(biāo)簽表達(dá)式。

          <div id="main">
              <div id="main_nav">
                  <div class="panel-group" id="accordion" style="margin-bottom: 0;">
                      <div th:each="menu, menuStat: ${menus}" th:if="${menu.children.size() != 0 && menu.children != null}" class="panel panel-default">
                          <div class="panel-heading">
                              <h4 class="panel-title">
                                  <p data-toggle="collapse" data-parent="#accordion" th:href="|#collapseOne${menuStat.index}|">
                                      <span th:text="${menu.name}">系統(tǒng)設(shè)置</span><span class="caret"></span>
                                  </p>
                              </h4>
                          </div>
                          <div th:if="${menuStat.first}" th:id="|collapseOne${menuStat.index}|" class="panel-collapse collapse collapse in">
                              <div class="panel-body">
                                  <p th:each="subMenu:${menu.children}" th:src="${subMenu.url}" th:text="${subMenu.name}">菜單管理</p>
                              </div>
                          </div>
                          <div th:if="${!menuStat.first}" th:id="|collapseOne${menuStat.index}|" class="panel-collapse collapse collapse">
                              <div class="panel-body">
                                  <p th:each="subMenu:${menu.children}" th:src="${subMenu.url}" th:text="${subMenu.name}">菜單管理</p>
                              </div>
                          </div>
                      </div>
                  </div>
                  <div id="nav_p">
                      <p th:each="menu:${menus}" th:if="${menu.children.size() == 0}" th:src="${menu.url}" th:text="${menu.name}">成績(jī)管理</p>
                  </div>
              </div>
              <div id="main_home">
                  首頁內(nèi)容
              </div>
          </div>

          測(cè)試應(yīng)用

          1、對(duì)應(yīng)效果展示

          用戶數(shù)據(jù)及對(duì)應(yīng)的角色

          管理員對(duì)應(yīng)的菜單權(quán)限。

          用戶角色對(duì)應(yīng)的菜單權(quán)限。

          測(cè)試用戶角色對(duì)應(yīng)的菜單權(quán)限。

          2、測(cè)試應(yīng)用

          用戶名為admin1有管理員角色的用戶登錄,菜單顯示。

          用戶名為admin2有用戶角色的用戶登錄,菜單顯示。

          用戶名為admin3有測(cè)試用戶角色的用戶登錄,菜單顯示。

          3、案例代碼下載

          下載地址:https://github.com/machaoyin/SpringBoot-Security

          來源:blog.csdn.net/qq_40205116/article/details/103739978

          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

          點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點(diǎn)這里好文分享給更多人↓↓

          瀏覽 25
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲最大的黄色视频 | 欧美在线观看网站 | 日本成人电影在线免费观看 | 成人先锋影音AV黄色电影网站 | 豆花av在线观看 豆花AV在线入口 豆花精品在线视频 |