• SpringBoot 20 Shiro授权的实现和整合Thymeleaf


    20.1 Shiro授权的实现


    1. 先写一个 未授权的 Controller,然后设置 没有授权会跳转的页面
        @RequestMapping("noauth")
        @ResponseBody
        public String unauthorized(){
            return "未经授权无法访问此页面";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    // perms[user:add] 必须得有 user:add 权限才可以 访问 /user/add
    filterMap.put("/user/add","perms[user:add]");
    // 未授权 会跳转的页面
    bean.setUnauthorizedUrl("/noauth");
    
    • 1
    • 2
    • 3
    • 4

    filterMap.put("/user/add","perms[user:add]");这个其实 就是 授权 最常用的监测点。就是通过授权 来判断你是否 可以访问页面!

    在这里插入图片描述
    在这里插入图片描述

    1. 在授权方法里面 赋予授权
        // 授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            System.out.println("执行了授权");
    
            // 授予用户 权限
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    
            simpleAuthorizationInfo.addStringPermission("user:add");
    
    
            return simpleAuthorizationInfo;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    这样的话,你会发现 无论你登录 哪个 用户 都会 去 赋予 授权。诶?这样不就 完蛋了吗?我们 必须 根据 用户 来 赋予给它 对应的授权呀。

    1. 数据库设计 perms 字段、role 字段 来 判断赋予的授权!

    在这里插入图片描述
    在这里插入图片描述

    首先 我们 肯定 要解决最大的难题,就是 授权那里,怎么能拿到 当前认证登录成功的用户呢??因为如果你拿不到。那肯定 是 无法 取出 对应的 permsrole 的呀。

    • 解决方案:分析 SimpleAuthenticationInfo(Principal,user.getPwd(),realmName);

    我们发现 第一个参数 是 信息主体,也就是 一个 对象。那么 我们想一下,认证登录的时候,什么玩意 是 信息的主体?答: user 对象,整个user 对象 就是 我们 需要的信息主体。

    所以我们 直接 传递 过去 就可以了。

    // 认证方法那里
    return new SimpleAuthenticationInfo(user,user.getPwd(),"userRealm");
    
    • 1
    • 2

    在这里插入图片描述
    然后 我们知道 SecurityUtils.getSubject(); 获取到的 subject 是独立的。所以 在授权方法那里 也是可以拿到的。

        // 授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            System.out.println("执行了授权");
    
            // 拿到 当前 登录的这个对象
            Subject subject = SecurityUtils.getSubject();
            // 拿到 信息主体 user 这个对象,因为我们 传递 就是 user 对象
            User user = (User)subject.getPrincipal();
    
            // 授予用户 权限
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    
            // 添加 用户的 权限
            simpleAuthorizationInfo.addStringPermission(user.getPerms());
            // 添加 用户的 角色
            simpleAuthorizationInfo.addRole(user.getRole());
    
    
            return simpleAuthorizationInfo;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    在这里插入图片描述

    我们正常开发的话,权限和角色不可能是一个。而一般情况下,我们都会把多个权限和角色的字符串拼接在一起。比如说 权限A|权限B 这样的方式,然后 用 split() 分割成 一个 String 的数组即可。


    20.2 整合 Thymeleaf

    其实 Shiro 整合 Thymeleaf,就是用来 做 授权控制页面渲染的

    1. 导入 依赖
            
            <dependency>
                <groupId>com.github.theborakompanionigroupId>
                <artifactId>thymeleaf-extras-shiroartifactId>
                <version>2.1.0version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 整合 shiroDialect
        // 整合 shiroDialect,为了 thymeleaf 做的
        @Bean
        public ShiroDialect shiroDialect(){
            return new ShiroDialect();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    3. 使用 命名空间 shiro:

    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>Titletitle>
    head>
    <body>
    <h1>首页h1>
    <p>[[${msg}]]p>
    <hr>
    <div shiro:hasPermission="user:add">
        <a th:href="@{/user/add}">adda>
    div>
    <div shiro:hasPermission="user:update">
        <a th:href="@{/user/update}">updatea>
    div>
    
    <a th:href="@{/user/logout}">注销a>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    1. 利用 subjec.getSession() 去编写 session

    因为我们 是 DefaultWebSessionManager 也就是 WEB 项目的 管理者,所以 此时 获取到的 session 就是 httpSession。这个 不用怀疑。

    在这里插入图片描述

    我们 直接可以 在 认证 这里 进行 session 节点的添加。

        // 认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("执行了认证");
    
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            User user = userService.getUserByName(token.getUsername());
    
            if(user == null){
                return null;// 这样的写法 会自动 抛出 异常 UnknowAccountException
            }
    
            // 设置一个 session 的键值对节点
    
            Subject subject = SecurityUtils.getSubject();
            Session session = subject.getSession();
            session.setAttribute("loginUser",user);
    
            // 密码认证,shiro 不让我们 开发者去做。它帮我们做。所以不用写
    
            return new SimpleAuthenticationInfo(user,user.getPwd(),"userRealm");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    subject.logout(); // 会自动 销毁 session
    在这里插入图片描述
    让其 没有 登陆过的,显示 登录,不显示注销。让其登陆过的,只显示 注销。

    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>Titletitle>
    head>
    <body>
    <h1>首页h1>
    <p>[[${msg}]]p>
    <hr>
    <div th:if="${session.loginUser == null}">
        <a th:href="@{/toLogin}">登录a>
    div>
    <div shiro:hasPermission="user:add">
        <a th:href="@{/user/add}">adda>
    div>
    <div shiro:hasPermission="user:update">
        <a th:href="@{/user/update}">updatea>
    div>
    <div th:if="!${session.loginUser == null}">
        <a th:href="@{/user/logout}">注销a>
    div>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Python学习笔记--对象的描述器
    45.【Java 实现双色球中奖查询系统】
    python中的四种数值交换方法(详解)
    如何使用 Loadgen 来简化 HTTP API 请求的集成测试
    第28章_瑞萨MCU零基础入门系列教程之基于面向对象的工程结构
    ✿✿✿JavaScript ---- 函数/js内置对象
    【杂七杂八】Windows和Linux怎么配置环境变量
    方法的使用
    台灯怎么选对眼睛好?精选眼科医生推荐护眼灯
    随手记录用的笔记本,记录一些常见成语和古文
  • 原文地址:https://blog.csdn.net/qq_52606908/article/details/126133349