栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

安全框架Shiro的简单学习

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

安全框架Shiro的简单学习

文章目录
  • Shiro
    • 1、什么是 Shiro
    • 2、功能介绍
    • 3、Shiro 架构
      • 3.1 Shiro 外部架构
      • 3.2 Shiro 内部架构
    • 4、Hello,Shiro
      • 4.1 快速实践
    • 5、Shiro 的 Subject 分析
    • 6、集成 SpringBoot
      • 6.1 搭建环境
      • 6.2 登陆拦截
      • 6.3 用户认证
      • 6.4 整合 MyBatis
      • 6.5 请求授权
      • 6.6 整合 Thymeleaf

Shiro 1、什么是 Shiro
  • Apache Shiro 是一个 java 的安全(权限)框架

  • Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境

  • Shiro 可以完成,认证,授权,加密,会话管理,Web 集成,缓存等等

  • Shiro 官方地址:http://shiro.apache.org/

  • 10 Minute Tutorial on Apache Shiro:http://shiro.apache.org/10-minute-tutorial.html

2、功能介绍

  • Authentication:身份认证、登录,验证用户是不是拥有相应的身份
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限,即判断用户能否进行什么操作,如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否具有某个权限
  • Session Manager:会话管理,即用户登录后就是第一次会话,在没有退出之前,它的所有信息都会存放在会话中,会话可以是普通的 JavaSE 环境,也可以是 Web 环境
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库中,而不是明文存储
  • Web Support:Web 支持,可以非常容易的集成到 Web 环境
  • Caching:缓存,比如用户登录后,其用户信息,拥有的角色、权限不必每次去查,这样可以提高效率
  • Concurrency:Shiro 支持多线程应用的并发验证,即:如在一个线程开启另一个线程,能把权限自动的传播过去
  • Testing:提供测试支持
  • Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
  • Remember Me:记住我功能,这是一个非常常见的功能,一次登录后,只要不注销,下次打开的话就不用登录
3、Shiro 架构 3.1 Shiro 外部架构

从外部来看 Shiro,即从应用程序角度来观察如何使用 食肉 完成工作:

  • subject:应用代码直接交互的对象是 Subject,也就是说 Shiro 的对外 API 核心就是 Subject,Subject 代表了当前的用户,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是 Subject,如网络爬虫,机器人等等,与 Subject 的所有交互都会委托给 SecurityManager;Subject 其实就是一个门面,SecurityManager 才是实际的执行者
  • SecurityManager:安全管理器,即所有与安全有关的操作都会与 SecurityManager 加护,并且它管理者所有的 Subject,可以看出它是 Shiro 的核心,它负责与 Shiro 的其他组件进行交互,它相当于 SpringMVC 的 DispatcherServlet 的角色
  • Realm:Shiro 从 Realm 获取安全数据(如用户,角色,权限),就是说 SecurityManager 要验证用户身份,那么他需要从 Realm 获取相应的用户进行比较,来确定用户的身份是否合法;也需要从 Realm 得到用户相应的角色、权限,进行验证用户的操作是否能够进行,可以吧 Realm 看成 DataSource
3.2 Shiro 内部架构

  • Subject:任何可以与用户交互的 ‘用户‘
  • Security Manager:相当于 SpringMVC 中的 DispatcherServlet;是 Shiro 的心脏,所有具体的交互都通过 SecurityManager 进行控制,他管理着所有的 Subject,且负责进行认证,授权,会话,以及缓存的管理
  • Authentication:负责 Subject 认证,是一个扩展点,可以自定义实现,可以使用认证策略(AuthenticationStrategy),即什么情况下算用户认证通过了
  • Authorizer:授权器,即访问控制器,用来决定主体是否有权进行相应的操作;即控制着用户访问应用中的哪些功能
  • Realm:可以有一个或者多个的 Realm,可以认为是安全实体数据源,即用户获取安全实体,可以用 JDBC 实现,也可以提取内存实现等等;由用户提供,所以一般在应用中都需要实现自己的 Realm
  • SessionManager:管理 Session 生命周期的组件,而 Shiro 并不仅仅可以用在 Web 环境,也可以用在普通的 JavaSE 环境中
  • CacheManager:缓存控制器,来管理如用户,角色,权限等缓存,因为这些数据基本很少改变,放到缓存中后可以提高访问的性能
  • Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于密码加密,以及解密等等
4、Hello,Shiro 4.1 快速实践

官方文档:http://shiro.apache.org/tutorial.html

官方 quickstart:https://github.com/apache/shiro/tree/main/samples/quickstart

快速搭建步骤:

  1. 创建一个 Maven 父工程,用于学习 Shiro,删掉 src

  2. 创建一个普通的 Maven 项目

  3. 根据官方文档,导入 shiro 依赖

    • 如果没有导入 log4j,那么就会默认使用 commons-logging
    
        org.apache.shiro
        shiro-core
        1.8.0
    
    
    
    
        org.slf4j
        jcl-over-slf4j
        2.0.0-alpha5
    
    
        org.slf4j
        slf4j-log4j12
        2.0.0-alpha5
        test
    
    
        log4j
        log4j
        1.2.17
    
    
  4. 在 resource 目录下,创建并将官网的内容编写入 log4j 的配置文件

    log4j.rootLogger=INFO, stdout
    
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
    
    # General Apache libraries
    log4j.logger.org.apache=WARN
    
    # Spring
    log4j.logger.org.springframework=WARN
    
    # Default Shiro logging
    log4j.logger.org.apache.shiro=INFO
    
    # Disable verbose logging
    log4j.logger.org.apache.shiro.util.ThreadContext=WARN
    log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
    
  5. 在 resource 目录下,创建并将官网的内容编写入 shiro.Ini 文件

    • 如果使用 IDEA 需要下载并安转 Ini 插件,否则看着不爽
    [users]
    # user 'root' with password 'secret' and the 'admin' role
    root = secret, admin
    # user 'guest' with the password 'guest' and the 'guest' role
    guest = guest, guest
    # user 'presidentskroob' with password '12345' ("That's the same combination on
    # my luggage!!!" ;)), and role 'president'
    presidentskroob = 12345, president
    # user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
    darkhelmet = ludicrousspeed, darklord, schwartz
    # user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
    lonestarr = vespa, goodguy, schwartz
    
    # -----------------------------------------------------------------------------
    # Roles with assigned permissions
    #
    # Each line conforms to the format defined in the
    # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
    # -----------------------------------------------------------------------------
    [roles]
    # 'admin' role has all permissions, indicated by the wildcard '*'
    admin = *
    # The 'schwartz' role can do anything (*) with any lightsaber:
    schwartz = lightsaber:*
    # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
    # license plate 'eagle5' (instance specific id)
    goodguy = winnebago:drive:eagle5
    
  6. 在 java 文件夹下,将官网的快速搭建粘入

    • 注意:新版中官方已经有更好的方法替代了之前的方法

      // 旧
      //import org.apache.shiro.ini.IniSecurityManagerFactory;
      //import org.apache.shiro.lang.util.Factory;
      
      // 新
      import org.apache.shiro.mgt.DefaultSecurityManager; // new
      import org.apache.shiro.realm.text.IniRealm; // new
      
      // 旧方法
      //Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
      //SecurityManager securityManager = factory.getInstance();
      
      // 新方法
      DefaultSecurityManager securityManager = new DefaultSecurityManager();
      IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
      securityManager.setRealm(iniRealm);
      
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    //import org.apache.shiro.ini.IniSecurityManagerFactory;
    import org.apache.shiro.mgt.DefaultSecurityManager; // new
    import org.apache.shiro.realm.text.IniRealm; // new
    import org.apache.shiro.mgt.SecurityManager;
    
    import org.apache.shiro.session.Session;
    import org.apache.shiro.subject.Subject;
    //import org.apache.shiro.lang.util.Factory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    
    
    public class Quickstart {
    
        private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
    
    
        public static void main(String[] args) {
    
            // The easiest way to create a Shiro SecurityManager with configured
            // realms, users, roles and permissions is to use the simple INI config.
            // We'll do that by using a factory that can ingest a .ini file and
            // return a SecurityManager instance:
    
            // Use the shiro.ini file at the root of the classpath
            // (file: and url: prefixes load from files and urls respectively):
    
            // 旧方法
            //Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            //SecurityManager securityManager = factory.getInstance();
            // 新方法
            DefaultSecurityManager securityManager = new DefaultSecurityManager();
            IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
            securityManager.setRealm(iniRealm);
    
            // for this simple example quickstart, make the SecurityManager
            // accessible as a JVM singleton.  Most applications wouldn't do this
            // and instead rely on their container configuration or web.xml for
            // webapps.  That is outside the scope of this simple quickstart, so
            // we'll just do the bare minimum so you can continue to get a feel
            // for things.
            SecurityUtils.setSecurityManager(securityManager);
    
            // Now that a simple Shiro environment is set up, let's see what you can do:
    
            // get the currently executing user:
            Subject currentUser = SecurityUtils.getSubject();
    
            // Do some stuff with a Session (no need for a web or EJB container!!!)
            Session session = currentUser.getSession();
            session.setAttribute("someKey", "aValue");
            String value = (String) session.getAttribute("someKey");
            if (value.equals("aValue")) {
                log.info("Retrieved the correct value! [" + value + "]");
            }
    
            // let's login the current user so we can check against roles and permissions:
            if (!currentUser.isAuthenticated()) {
                UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
                token.setRememberMe(true);
                try {
                    currentUser.login(token);
                } catch (UnknownAccountException uae) {
                    log.info("There is no user with username of " + token.getPrincipal());
                } catch (IncorrectCredentialsException ice) {
                    log.info("Password for account " + token.getPrincipal() + " was incorrect!");
                } catch (LockedAccountException lae) {
                    log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                            "Please contact your administrator to unlock it.");
                }
                // ... catch more exceptions here (maybe custom ones specific to your application?
                catch (AuthenticationException ae) {
                    //unexpected condition?  error?
                }
            }
    
            //say who they are:
            //print their identifying principal (in this case, a username):
            log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
    
            //test a role:
            if (currentUser.hasRole("schwartz")) {
                log.info("May the Schwartz be with you!");
            } else {
                log.info("Hello, mere mortal.");
            }
    
            //test a typed permission (not instance-level)
            if (currentUser.isPermitted("lightsaber:wield")) {
                log.info("You may use a lightsaber ring.  Use it wisely.");
            } else {
                log.info("Sorry, lightsaber rings are for schwartz masters only.");
            }
    
            //a (very powerful) Instance Level permission:
            if (currentUser.isPermitted("winnebago:drive:eagle5")) {
                log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                        "Here are the keys - have fun!");
            } else {
                log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
            }
    
            //all done - log out!
            currentUser.logout();
    
            System.exit(0);
        }
    }
    
  7. 启动,发现打印了日志信息

  8. 表明,quickstart 完成

问题:

  • 运行时报错

  • 问题原因以及解决办法

5、Shiro 的 Subject 分析
  1. 获取当前的用户对象 Subject

    Subject currentUser = SecurityUtils.getSubject();
    
  2. 通过当前用户拿到 session,并在 session 中设置至,以及获取值

    Session session = currentUser.getSession();
    session.setAttribute("someKey", "aValue");
    String value = (String) session.getAttribute("someKey");
    if (value.equals("aValue")) {
        log.info("Retrieved the correct value! [" + value + "]");
    }
    
  3. 判断当前用户是否被认证

    if (!currentUser.isAuthenticated()) {
        // Token:令牌
        UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
        // 设置记住我
        token.setRememberMe(true);
        try {
            // 执行登录操作
            currentUser.login(token);
        } catch (UnknownAccountException uae) { // 用户名错误
            log.info("There is no user with username of " + token.getPrincipal());
        } catch (IncorrectCredentialsException ice) { // 密码错误
            log.info("Password for account " + token.getPrincipal() + " was incorrect!");
        } catch (LockedAccountException lae) { // 多次用户密码错误,就会被锁定
            log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                     "Please contact your administrator to unlock it.");
        }
        // ... catch more exceptions here (maybe custom ones specific to your application?
        catch (AuthenticationException ae) { // 认证是否成功
            //unexpected condition?  error?
        }
    }
    
  4. 获取当前用户认证

    log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
    
  5. 判断当前是否拥此角色

    • 角色都在 shiro.Ini 中配置
    if (currentUser.hasRole("schwartz")) {
        log.info("May the Schwartz be with you!");
    } else {
        log.info("Hello, mere mortal.");
    }
    
  6. 检测拥有什么权限

    • 权限也是在 shiro.Ini 中配置

    • 粗粒度

      if (currentUser.isPermitted("lightsaber:wield")) {
          log.info("You may use a lightsaber ring.  Use it wisely.");
      } else {
          log.info("Sorry, lightsaber rings are for schwartz masters only.");
      }
      
    • 细粒度

      if (currentUser.isPermitted("winnebago:drive:eagle5")) {
          log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                   "Here are the keys - have fun!");
      } else {
          log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
      }
      
  7. 注销

    //all done - log out!
    currentUser.logout();
    
  8. 结束

    System.exit(0);
    
6、集成 SpringBoot 6.1 搭建环境

  1. 创建一个新的 springboot 项目,导入 spring web 依赖

  2. 导入 thymeleaf 依赖

    
        org.springframework.boot
        spring-boot-starter-thymeleaf
    
    
  3. 创建 config 目录,编写 Shiro 配置文件:ShiroConfig

    • 最好从后往前写
    • 通常 ShiroFilterFactoryBean 实现请求过滤,而 UserRealm 来进行真正的权限过滤
    package com.aze.config;
    
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class ShiroConfig {
    
        // 3. ShiroFilterFactoryBean
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            // 设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            return bean;
        }
    
        // 2. DefaultWebSecurityManager
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager getDDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            // 关联 UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
        // 1. 创建 realm 对象,需要自定义类
        @Bean(name = "userRealm")
        public UserRealm userRealm(){
            return new UserRealm();
        }
    
    }
    
  4. 自定义 UserReaml,需要继承 AuthorizingRealm

    package com.aze.config;
    
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    
    // 自定义 UserReaml 需要继承 AuthorizingRealm
    public class UserRealm extends AuthorizingRealm {
        // 授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了=>授权 doGetAuthorizationInfo");
            return null;
        }
        // 认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("执行了=>认证 doGetAuthenticationInfo");
            return null;
        }
    }
    
  5. 编写前端的测试页面

    • index

      
      
      
          
          Title
      
      
      
      

      首页


      add | update
    • add

      
      
      
          
          Title
      
      
      
      

      add

    • update

      
      
      
          
          Title
      
      
      
      

      update

  6. 创建 controller 目录,编写 MyController

    package com.aze.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class MyController {
    
        @RequestMapping({"/","/index","/index.html"})
        public String toIndex(Model model){
            model.addAttribute("msg","hello,shiro!");
            return "index";
        }
    
        @RequestMapping("/user/add")
        public String add(){
            return "/user/add";
        }
    
        @RequestMapping("/user/update")
        public String update(){
            return "/user/update";
        }
    }
    
  7. 启动项目,进行测试

  8. 环境搭建成功

6.2 登陆拦截
  1. 编写登录页面 login.html

    
    
    
        
        Title
    
    
    
    

    登录


    账号:
    密码:
  2. 在 MyController 中添加登录的跳转

    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }
    
  3. shiro 内置过滤器

    • anon:不需要认证就可以访问
    • authc:必须要认证了才可以访问
    • user:必须拥有“记住我”功能才可以使用
    • perms:拥有对某个资源的权限才可以访问
    • role:拥有某个角色的权限才可以访问
  4. 在 shiro 配置文件中,添加登录拦截的相关过滤器

    // 添加 shiro 的内置过滤器
    Map filterMap = new linkedHashMap<>();
    // 将 /user 下的所有路径都需要登录认证
    filterMap.put("/user
            Map filterMap = new linkedHashMap<>();
    
            // 授权,正常情况下,没有授权会跳转到未授权页面
            filterMap.put("/user/add","perms[user:add]");
            filterMap.put("/user/update","perms[user:update]");
    
            //filterMap.put("/user/add","authc");
            //filterMap.put("/user/update","authc");
            filterMap.put("/user/*","authc");
            bean.setFilterChainDefinitionMap(filterMap);
    
            // 设置登录请求
            bean.setLoginUrl("/toLogin");
            // 设置未授权页面
            bean.setUnauthorizedUrl("/noauth");
            return bean;
        }
    
        // 2. DefaultWebSecurityManager
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            // 关联 UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
        // 1. 创建 realm 对象,需要自定义类
        @Bean(name = "userRealm")
        public UserRealm userRealm(){
            return new UserRealm();
        }
    
    }
    

  5. 在 MyController 中添加未授权页面的请求

    @RequestMapping("/noauth")
    @ResponseBody
    public String unauthorized(){
        return "未经授权无法访问此页面!";
    }
    
  6. 编写用户的授权(UserRealm)

    package com.aze.config;
    
    import com.aze.pojo.User;
    import com.aze.service.UserService;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    
    // 自定义 UserReaml 需要继承 AuthorizingRealm
    public class UserRealm extends AuthorizingRealm {
    
        @Autowired
        UserService userService;
    
        // 授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了=>授权 doGetAuthorizationInfo");
    
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            //info.addStringPermission("user:add");
    
            // 取得当前登录的对象
            Subject subject = SecurityUtils.getSubject();
            User currentUser = (User) subject.getPrincipal();
    
            info.addStringPermission(currentUser.getPerms());
    
            return info;
        }
        // 认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("执行了=>认证 doGetAuthenticationInfo");
    
            UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
    
            // 连接数据库
            User user = userService.queryUserByName(userToken.getUsername());
            if (user == null){
                // 如果没有这个用户,则报出异常 UnknownAccountException
                return null;
            }
    
            // 密码认证,shiro 会自动帮你做了
            return new SimpleAuthenticationInfo(user,user.getPwd(),"");
        }
    }
    

  7. 修改数据库,增添权限

  8. 修改实体类

    package com.aze.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
    
        private Integer id;
        private String name;
        private String pwd;
        // 增添
        private String perms;
    
    }
    
  9. 测试不同用户权限

6.6 整合 Thymeleaf
标签说明
shiro:guest用户没有身份验证时显示相应信息,即游客访问信息
shiro:user用户已经身份验证/记住我登录后显示相应的信息
shiro:authenticated用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的
shiro:notAuthenticated用户已经身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证
shiro: principal相当于((User)Subject.getPrincipals()).getUsername()
shiro:lacksPermission如果当前Subject没有权限将显示body体内容
shiro:hasRole如果当前Subject有角色将显示body体内容
shiro:hasAnyRoles如果当前Subject有任意一个角色(或的关系)将显示body体内容
shiro:lacksRole如果当前Subject没有角色将显示body体内容
shiro:hasPermission是否拥有此权限 如果当前Subject有权限将显示body体内容
  1. 导入 thymeleaf-extras-shiro 依赖

    
        com.github.theborakompanioni
        thymeleaf-extras-shiro
        2.1.0
    
    
  2. 在 shiro 配置文件(ShiroConfig)中,增添 shiro 与 thymeleaf 的整合配置

    // 整合 shiroDialect:用来整合 shiro 与 thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
    
  3. 修改首页前端代码

    
    
    
        
        Title
    
    
    
    

    首页

    登录 注销


    add

  4. 启动项目进行测试

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/489970.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号