zoukankan      html  css  js  c++  java
  • 7.2 Shiro

    一.Shiro简介

    1.什么是Shiro

    • Apache Shiro是一个Java安全(权限)框架

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

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

    • 下载地址:http://shiro.apache.org

    2.功能

    • Authentication:身份认证、登录、验证用户是不是拥有相应的身份

    • Authorization:授权,即权限验证,验证某个已认证用户是否拥有某个权限,判断用户能否进行什么操作,例如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否具有某个权限

    • Session Manager:会话管理,即用户登录后就是第一次会话,在没有退出之前,它的所有信息都在绘画中;会话可以是普通的JavaSE环境,也可以是Web环境

    • Cryptography:加密,保护数据的安全性,如密码加密存储在数据库中,而不是明文存储

    • Web Support:Web支持,可以非常容易集成到Web环境

    • Caching:缓存,比如用户登录后,其用户信息,拥有的角色、权限不比每次去查,这样可以提高效率

    • Concurrency:Shiro支持多线程应用的并发验证,即在一个线程中开启另一个线程,能把权限自动的传播过去

    • Testing:提供测试支持

    • Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问

    • Remember Me:记住我,即一次登录后下次就不用再登录了

    3.Shiro架构(外部)

    (1)从应用程序角度来观察如何使用shiro完成工作:

    (2)核心对象

    • 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。

    4.Shiro框架(内部)

    二.Shiro快速开始

    1.步骤

    • 搭建普通maven项目(略)

    • pom.xml中导入依赖

    • 编写配置文件shiro.ini和log4j.propreties

    • 编写Java类

    • 测试执行

    2.pom.xml中导入依赖

    <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.1</version>
        </dependency>
    
        <!-- configure logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

    3.编写配置文件shiro.ini和log4j.propreties放到resources目录下

    shiro.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

    log4j.propreties

    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

    4.编写Java类

    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.config.IniSecurityManagerFactory;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.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) {
    
    
            // 读取配置文件
            Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);
    
    
            //获取当前的用户对象Subject
            Subject currentUser = SecurityUtils.getSubject();
    
            //通过当前用户对象拿到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 + "]");
            }
    
            //判断当前的用户对象是否被认证
            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?
                }
            }
    
            //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);
        }
    }

    5.测试执行

    6.主要的代码分析

    Subject currentUser = SecurityUtils.getSubject();//获取当前的用户对象Subject
    Session session = currentUser.getSession();//通过当前用户对象拿到Session
    currentUser.isAuthenticated();//判断当前的用户对象是否被认证
    token.setRememberMe(true);  //记住我
    currentUser.login(token);   //执行登录操作
    token.getPrincipal();//获得token认证
    currentUser.getPrincipal();//获得当前用户的认证
    currentUser.hasRole("schwartz");//是否拥有xxx角色
    currentUser.isPermitted("lightsaber:wield");//是否拥有xxx权限
    currentUser.logout();//注销

    三.SpringBoot集成Shiro

    1.步骤

    • 搭建springboot项目环境带mvc和thymeleaf(略)

    • pom.xml中导入依赖

    • 编写Java Config配置

    • 编写控制器

    • 编写页面

    2.pom.xml中导入依赖

    <!--shiro整合spring的包-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.5.1</version>
    </dependency>

    3.编写Java Config配置

     添加config包,在config包中添加UserRealm.java

    • 用于授权和认证

    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;
    
    //自定义的UserRealm需要继承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("执行了=>认证doGetAuthorizationInfo");
            return null;
        }
    }

    在config包中添加ShiroConfig.java

    • 创建三个bean用于Shiro管理

    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 {
    
        /*
            Subject: 用户
            SecurityManager:管理所有用户
            Realm:连接数据
        */
    
        //ShiroFilterFactoryBean
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
    
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            return bean;
        }
    
    
        //DefaultWebSecurityManager
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    
            //关联userRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
    
    
        //创建Realm对象,需要自定义的Realm对象
        @Bean
        public UserRealm userRealm(){
            return new UserRealm();
        }
    
    }

    4.编写控制器

    • 添加controller包并在其中添加MyController.java

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class MyController {
    
        @RequestMapping({"/","/index"})
        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";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin(){
            return "login";
        }
    }

    5.编写页面

    index.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    <h1>首页</h1>
    
    <p th:text="${msg}"></p>
    
    <hr>
    
    <a th:href="@{/user/add}">add</a> |  <a th:href="@{/user/update}">update</a>
    </body>
    </html>
    View Code

    add.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>add</h1>
    </body>
    </html>
    View Code

    update.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>update</h1>
    </body>
    </html>
    View Code

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>login</title>
    </head>
    <body>
    
    <h1>登录</h1>
    
    <hr>
    
    <form action="">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="text" name="password"></p>
        <p><input type="submit"></p>
    </form>
    </body>
    </html>
    View Code

    基本环境搭建成功!

    四.Shiro实现登录拦截

    1.修改ShiroConfig.java文件

    • 设置对user路径下的所有文件必须认证才能访问

    • 如果认证失败跳转登录页

    //ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
    
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
    
        /*
            anno: 无需认证就可以登录
            authc:必须认证了才能访问
            user:必须拥有记住我功能才能访问
            perms:拥有对某个资源的权限才能访问
            role:拥有某个角色权限才能访问
         */
    
        Map<String,String> filterMap = new LinkedHashMap<>();
    
    //        filterMap.put("/user/add","authc");
    //        filterMap.put("/user/update","authc");
        filterMap.put("/user/*","authc");
    
        bean.setFilterChainDefinitionMap(filterMap);
    
        //设置登录的请求
        bean.setLoginUrl("/toLogin");
    
        return bean;
    }

    五.Shiro实现用户认证集成Mybatis

    1.步骤

    • pom.xml中添加依赖

    • 连接数据库配置pojo,mapper,service层以及xxxMapper.xml(略)

    • 修改登录页面

    • 编写application.yml

    • 控制其中添加方法

    • UserRealm.java中修改认证方法

    2.pom.xml中添加依赖

    • MySQL、Mybatis、Druid、log4j、lombok

    <!--MySQL-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- 引入 myBatis,这是 MyBatis官方提供的适配 Spring Boot 的,而不是Spring Boot自己的-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.0</version>
    </dependency>
    
    <!--Druid-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.21</version>
    </dependency>
    
    <!--Log4j-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    View Code

    3.修改登录页面

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>login</title>
    </head>
    <body>
    
    <h1>登录</h1>
    
    <hr>
    <p th:text="${msg}" style="color:red"></p>
    <form th:action="@{/login}" method="post">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="text" name="password"></p>
        <p><input type="submit"></p>
    </form>
    </body>
    </html>

    4.编写application.yml

    • 注意数据库连接以及Mybatis配置的路径

    spring:
      datasource:
        username: root
        password: 123456
        #?serverTimezone=UTC解决时区的报错
        url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource
    
        #Spring Boot 默认是不注入这些属性值的,需要自己绑定
        #druid 数据源专有配置
        initialSize: 5
        minIdle: 5
        maxActive: 20
        maxWait: 60000
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
    
        #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
        #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
        #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
        filters: stat,wall,log4j
        maxPoolPreparedStatementPerConnectionSize: 20
        useGlobalDataSourceStat: true
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
    
    #指定myBatis的核心配置文件与Mapper映射文件
    mybatis:
      mapper-locations: classpath:mapper/*.xml
      # 注意:对应实体类的路径
      type-aliases-package: ustc.wzh.pojo
    View Code

    5.控制其中添加方法

    • 此方法接收表单提交的用户名和密码

    • 将用户名和密码生成Token交给subject处理会进入验证方法中判断最后返回给此方法,如果验证成功进入index页面失败则还是login页面

    @RequestMapping("/login")
    public String login(String username, String password, Model model) {
    
        //获得当前的用户
        Subject subject = SecurityUtils.getSubject();
    
        //封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    
        try {
            //执行登录的方法
            subject.login(token);
            return "index";
        } catch (UnknownAccountException e) {
            //用户名不存在
            model.addAttribute("msg", "用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e) {
            //密码不存在
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    
    }

    6.UserRealm.java中修改认证方法

    • 需要先自动装配业务层才能拿到用户对象

    @Autowired
    UserService userService;
    • 从方法参数中获得的Token中拿出用户名,然后在数据库中查找,最后判断用户是否不存在,如果不存在返回null则控制器就会异常处理,存在就跳转
    • 此处还可以设置加密方式(https://blog.csdn.net/qq_21046965/article/details/90105915)
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证doGetAuthorizationInfo");
    
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
    
        //连接数据库
        User user = userService.queryUserByName(userToken.getUsername());
    
        if (user == null) {
            return null;    //没有获得用户则返回null经过ShiroConfig类中的方法会抛出UnknownAccountException
        }
    
        //还可以设置加密方式
        return new SimpleAuthenticationInfo("", user.getPwd(), "");
    }

    六.Shiro实现用户授权

    1.步骤

    • 控制器添加未授权跳转方法

    • UserRealm.java修改授权方法

    • ShiroConfig.java中修改拦截器方法

    2.控制器添加未授权跳转方法

    @RequestMapping("/unauth")
    @ResponseBody
    public String unauthorized(){
        return "未经授权无法访问";
    }

    3.UserRealm.java修改授权方法

    • 先修改认证方法返回参数添加一个user用于传递用户对象

    return new SimpleAuthenticationInfo(user, user.getPwd(), "");
    • 修改授权方法获得数据库中用户的授权

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
        System.out.println("执行了=>授权doGetAuthorizationInfo");
    
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
        //获得当前的登录对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal(); //获得认证方法中保存的登录对象
    
        //设置当前用户对象权限
        /*
            需要在数据库中设置一个权限的属性来控制
            此处省去麻烦就直接通过用户名来设置权限
        */
        //给root授权
        if (Objects.equals(currentUser.getName(),"root")){
            info.addStringPermission("user:add"); //添加add权限
            System.out.println("root用户授权add");
        }
    
        //给张三授权
        if (Objects.equals(currentUser.getName(),"张三")){
            info.addStringPermission("user:update"); //添加add权限
            System.out.println("张三用户授权update");
    
        }
    
        return info;
    }

    4.ShiroConfig.java中修改拦截器方法

    • 对于不同权限进行拦截

    //ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
    
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
    
        /*
            anno: 无需认证就可以登录
            authc:必须认证了才能访问
            user:必须拥有记住我功能才能访问
            perms:拥有对某个资源的权限才能访问
            role:拥有某个角色权限才能访问
         */
    
        //拦截
        Map<String, String> filterMap = new LinkedHashMap<>();
    
        //        filterMap.put("/user/add","authc");
        //        filterMap.put("/user/update","authc");
    
    
    
        //只有权限为user:add的用户才可以访问user/add
        filterMap.put("/user/add","perms[user:add]");
        //只有权限为user:update的用户才可以访问user/update
        filterMap.put("/user/update","perms[user:update]");
    
        //只有通过认证的用户才可以访问user目录下的文件
        filterMap.put("/user/*", "authc");
    
        //设置拦截链
        bean.setFilterChainDefinitionMap(filterMap);
    
        //设置未授权的页面
        bean.setUnauthorizedUrl("/unauth");
    
        //设置登录的请求
        bean.setLoginUrl("/toLogin");
    
        return bean;
    }

    5.测试成功

    七.Shiro整合Thymeleaf

    1.步骤:通过判断用户的权限显示不同的页面

    • pom.xml中导入配置

    • ShiroConfig.java添加一个shiro与thymeleaf结合使用的bean

    • 修改index页面

    2.pom.xml中导入配置

    <!--thymeleaf和shiro整合-->
    <dependency>
        <groupId>com.github.theborakompanioni</groupId>
        <artifactId>thymeleaf-extras-shiro</artifactId>
        <version>2.0.0</version>
    </dependency>

    3.ShiroConfig.java添加一个shiro与thymeleaf结合使用的bean

    //整合ShiroDialect:用于shiro整合thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

    4.修改index页面

    • 添加对thymeleaf和shiro的约束:

       xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" 

    • 判断是否登录: th:if="${session.loginUser == null}" 

    • 判断是否有权限: shiro:hasPermission="user:add" 

    • <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h1>首页</h1> <div th:if="${session.loginUser == null}"> <a th:href="@{/toLogin}">登录</a> </div> <p th:text="${msg}"></p> <hr> <div shiro:hasPermission="user:add"> <a th:href="@{/user/add}">add</a> </div> <div shiro:hasPermission="user:update"> <a th:href="@{/user/update}">update</a> </div> </body> </html>

    5.测试成功!

  • 相关阅读:
    格式化数字,将字符串格式的数字,如:1000000 改为 1 000 000 这种展示方式
    jquery图片裁剪插件
    前端开发采坑之安卓和ios的兼容问题
    页面消息提示,上下滚动
    可以使用css的方式让input不能输入文字吗?
    智慧农村“三网合一”云平台测绘 大数据 农业 信息平台 应急
    三维虚拟城市平台测绘 大数据 规划 三维 信息平台 智慧城市
    农业大数据“一张图”平台测绘 大数据 房产 国土 农业 信息平台
    应急管理管理局安全生产预警平台应急管理系统不动产登记 测绘 大数据 规划 科教 三维 信息平台
    地下综合管廊管理平台测绘 大数据 地下管线 三维 信息平台
  • 原文地址:https://www.cnblogs.com/zhihaospace/p/12416885.html
Copyright © 2011-2022 走看看