Shiro整合EhCache缓存(二)

Shiro整合EhCache缓存

  • 1、授权、角色认证
    • 1.1、后端接口服务注解
    • 1.2、授权-获取角色
    • 1.3、授权-获取权限
    • 1.4、授权-异常处理
    • 1.5、前端页面授权
  • 2、EhCache
    • 2.1、Shiro整合EhCache

1、授权、角色认证

用户登录后,需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判断,这个工具就是Reaml的doGetAuthorizationInfo方法进行判断,触发权限判断的有两种方式:

  1. 在页面中通过shiro:****属性判断
  2. 在接口服务中通过注解@Requires****进行判断

1.1、后端接口服务注解

通过给接口服务方法添加注解可以实现权限校验,可以加在控制器方法上,也可以加在业务方法上,一般加在控制器方法上。常用注解如下:

  1. @RequiresAuthentication : 验证用户是否登录,等同于方法subject.isAuthenticated()

  2. @RequiresUser : 验证用户是否被记忆,登录认证成功subject.isAuthenticated() 为true,登录后被记忆subject.isRemembered()为true

  3. @RequiresGuest : 验证是否是一个 guest 游客的请求,此时subject.getPrincipal()为 null

  4. @RequiresRoles :验证subject是否有相应角色,有角色访问方法,没有则会抛出异常

    AuthorizationException ,例如

    // 只有subject有aRoleName角色才能访问方法someMethod()
    @RequiresRoles("aRoleName")
    void someMethod();
    
  5. @RequiresPermissions:验证 subject 是否有相应权限,有权限访问方法,没有则会抛出异常 AuthorizationException ,例如

// subject 必须同时含有 file:read 和 write:a.txt 权限才能访问方法 someMethod()
@RequiresPermissions("file:read","write:a.txt")
void someMethod();

1.2、授权-获取角色

  1. 添加controller方法
/**
 * 授权admin角色
 * @return
 */
@RequiresRoles({"admin"})
@GetMapping("userLoginRoles")
@ResponseBody
public String userLoginRoles() {
    System.out.println("登录认证验证角色");
    return "验证角色成功";
}
  1. 修改main.html
<h1>Shiro 登录认证后主页面</h1>
<br>
登录用户为:<span th:text="${session.user}"></span>
<a href="/logout">退出登录</a>
<br>
<a href="/LoginController/userLoginRoles">测试授权</a>
  1. 修改CustomerRealm方法
/**
 * 自定义授权方法:获取当前登录用户权限信息,返回给Shiro用来进行授权对比
 * @param principalCollection
 * @return
 */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("进入自定义授权方法");
    //1.创建对象,存储当前登录的用户的权限和角色
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //2.存储角色
    info.addRole("admin");
    //3.返回
    return info;
}
  1. 访问:localhost:8080/LoginController/login 输入账号密码,点击测试授权,显示验证角色成功,说明张三具有admin的角色

在这里插入图片描述

接下来我们结合数据库

  1. 创建库表
CREATE TABLE `role` (
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
 `name` VARCHAR(30) DEFAULT NULL COMMENT '角色名',
 `desc` VARCHAR(50) DEFAULT NULL COMMENT '描述',
 `realname` VARCHAR(20) DEFAULT NULL COMMENT '角色显示名',
 PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色表';

INSERT INTO `role` VALUES (1, 'admin', '所有权限', '管理员');
INSERT INTO `role` VALUES (2, 'userManager', '用户管理权限', '用户管理员');

CREATE TABLE `role_user` (
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
 `uid` BIGINT(20) DEFAULT NULL COMMENT '用户 id',
 `rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id',
 PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色用户映射
表';

INSERT INTO `role_user` VALUES (1, 1, 1);
INSERT INTO `role_user` VALUES (2, 1, 2);
INSERT INTO `role_user` VALUES (3, 2, 2);

在这里插入图片描述

  1. 根据用户名查询对应角色信息
SELECT NAME FROM role WHERE id IN (SELECT rid FROM role_user WHERE 
uid=(SELECT id FROM USER WHERE NAME='张三'));
  1. mapper方法
@Repository
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据用户查询对应角色信息
     * @param principal
     * @return
     */
    @Select("select name from role where id in(select rid from role_user where uid=(select id from user where name = #{principal}))")
    List<String> getUserRoleInfoMapper(@Param("principal")String principal);

}
  1. service接口
public interface UserService {
    /**
     * 用户登录
     * @param name
     * @return
     */
    User getUserInfoByName(String name);

    /**
     * 根据用户查询角色信息
     * @param principal
     * @return
     */
    List<String> getUserRoleInfo(String principal);
}

实现类:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;


    /**
     * 用户登录
     * @param name
     * @return
     */
    @Override
    public User getUserInfoByName(String name) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name",name);
        User user = userMapper.selectOne(wrapper);
        return user;
    }

    /**
     * 根据用户查询角色信息
     * @param principal
     * @return
     */
    @Override
    public List<String> getUserRoleInfo(String principal) {
        return userMapper.getUserRoleInfoMapper(principal);
    }
}
  1. CustomerRealm自定义Realm改造,改为从数据库中获取信息
/**
 * 自定义授权方法:获取当前登录用户权限信息,返回给Shiro用来进行授权对比
 * @param principalCollection
 * @return
 */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("进入自定义授权方法");
    //1.获取当前用户身份信息
    String principal = principalCollection.getPrimaryPrincipal().toString();
    //2.调用接口方法获取用户的角色信息(从数据库)
    List<String> roles = userService.getUserRoleInfo(principal);
    System.out.println("当前用户角色信息:" + roles);
    //3.创建对象,存储当前登录的用户的权限和角色
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //4. 存储角色
    info.addRole("admin");
    //3.返回
    return info;
}
  1. 访问:localhost:8080/LoginController/login 输入账号密码,点击测试授权,显示验证角色成功

在这里插入图片描述

1.3、授权-获取权限

  1. 创建数据库表
CREATE TABLE `permissions` (
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
 `name` VARCHAR(30) DEFAULT NULL COMMENT '权限名',
 `info` VARCHAR(30) DEFAULT NULL COMMENT '权限信息',
 `desc` VARCHAR(50) DEFAULT NULL COMMENT '描述',
 PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='权限表';

INSERT INTO `permissions` VALUES (1, '删除用户', 'user:delete', '删除用户');
INSERT INTO `permissions` VALUES (2, '新增用户', 'user:add', '新增用户');
INSERT INTO `permissions` VALUES (3, '修改用户', 'user:edit', '修改用户');

CREATE TABLE `role_ps` (
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
 `rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id',
 `pid` BIGINT(20) DEFAULT NULL COMMENT '权限 id',
 PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色权限映射
表';
INSERT INTO `role_ps` VALUES (1, 1, 1);
INSERT INTO `role_ps` VALUES (2, 1, 2);
INSERT INTO `role_ps` VALUES (3, 1, 3);

在这里插入图片描述

  1. 根据角色名查询对应权限信息
SELECT info FROM permissions WHERE id IN (SELECT pid FROM role_ps WHERE rid 
IN (SELECT id FROM role WHERE NAME IN('admin','userMag')));
  1. mapper方法
/**
 * 根据角色名查询对应权限信息
 * @param roles
 * @return
 */
@Select({
        "<script>",
        "select info from permissions where id in",
        "(select pid from role_ps where rid in (",
        "select id from role where name in",
        "<foreach collection='roles' item='name' open='(' separator=',' close=')'>",
        "#{name}",
        "</foreach>",
        "))",
        "</script>"
})
List<String> getUserPermissionInfoMapper(@Param("roles")List<String> roles);
  1. Service接口
/**
* 根据用户获取用户角色的权限信息
* @return
*/
List<String> getUserPermissionInfo(List<String> roles);

实现类:

/**
 * 根据用户获取用户角色的权限信息
 */
@Override
public List<String> getUserPermissionInfo(List<String> roles) {
    return userMapper.getUserPermissionInfoMapper(roles);
}
  1. CustomerRealm自定义Realm改造
/**
 * 自定义授权方法:获取当前登录用户权限信息,返回给Shiro用来进行授权对比
 * @param principalCollection
 * @return
 */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("进入自定义授权方法");
    //1.获取当前用户身份信息
    String principal = principalCollection.getPrimaryPrincipal().toString();
    //2.调用接口方法获取用户的角色信息(从数据库)
    List<String> roles = userService.getUserRoleInfo(principal);
    System.out.println("当前用户角色信息:" + roles);
    //调用接口方法获取用户角色的权限信息
    List<String> permissions = userService.getUserPermissionInfo(roles);
    System.out.println("当前用户权限信息:" + permissions);
    //3.创建对象,存储当前登录的用户的权限和角色
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //4. 存储角色
    info.addRole("admin");
    //5. 存储权限
    info.addStringPermissions(permissions);
    //3.返回
    return info;
}
  1. 添加controller方法,注解设置角色权限
/**
 * 根据用户获取用户角色的权限信息,验证是否具有 user:delete 权限
 * @return
 */
@RequiresPermissions("user:delete")
@GetMapping("userPermissions")
@ResponseBody
public String userLoginPermissions() {
    System.out.println("登录认证验证权限");
    return "验证权限成功";
}
  1. 改造main.html
<h1>Shiro 登录认证后主页面</h1>
<br>
登录用户为:<span th:text="${session.user}"></span>
<a href="/logout">退出登录</a>
<br>
<a href="/LoginController/userLoginRoles">测试授权-角色验证</a>
<a href="/LoginController/userPermissions">测试授权-权限验证</a>
  1. 访问:localhost:8080/LoginController/login 输入账号密码,点击测试授权-权限授权,

在这里插入图片描述

1.4、授权-异常处理

  • 创建认证异常处理类

    src/main/java/com/kuang/shiro/controller/PermissionsException.java

    使用@ControllerAdvice@ExceptionHandler实现特殊异常处理。

@ControllerAdvice
public class PermissionsException {

    @ResponseBody
    @ExceptionHandler(UnauthorizedException.class)
    public String unauthorizedException(Exception e){
        return "无权限";
    }

    @ResponseBody
    @ExceptionHandler(AuthorizationException.class)
    public String authorizationException(Exception e){
        return "权限认证失败";
    }
}

这样就会在网页直接显示无权限,权限认证失败,而不是一堆异常。但是我们思考一个问题,我们如果展示了所有功能,只有部分用户可以点进来查看,其他没有权限的用户点进来是无权限,这显然体验感不好,我们要求对不同权限用户展示不同的功能。

1.5、前端页面授权

  1. 添加依赖
<!--配置 Thymeleaf 与 Shiro 的整合依赖-->
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.1.0</version>
</dependency>
  1. ShiroConfig添加新配置
/**
 * 用于解析thymeleaf中的  shiro:相关属性
 */
@Bean
public ShiroDialect shiroDialect() {
    return new ShiroDialect();
}
  1. Thymeleaf中常用的 shiro:属性
<!--guest标签:用户没有身份验证时显示相应信息,即游客访问信息-->
<shiro:guest>
</shiro:guest>

<!--user标签:用户已经身份验证/记住我登录后显示相应的信息-->
<shiro:user>
</shiro:user>

<!--authenticated标签:用户已经身份验证通过,即 Subject.login 登录成功,不是记住我登录的-->
<shiro:authenticated>
</shiro:authenticated>

<!--notAuthenticated标签:用户已经身份验证通过,即没有调用 Subject.login 进行登录,包括记住我自动登录的也属于未进行身份验证-->
<shiro:notAuthenticated>
</shiro:notAuthenticated>

<!--principal标签:相当于((User)Subject.getPrincipals()).getUsername()-->
<shiro:principal>
</shiro:principal>

<!--hasRole标签:如果当前 Subject 有角色将显示 body 体内容-->
<shiro:hasRole name="admin">
</shiro:hasRole>

<!--hasAnyRoles标签:如果当前 Subject 有任意一个角色(或的关系)将显示 body 体内容-->
<shiro:hasAnyRoles name="admin,user">
</shiro:hasAnyRoles>

<!--hasPermission标签:如果当前 Subject 有权限将显示 body 体内容-->
<shiro:hasPermission name="user:create">
</shiro:hasPermission>
  1. 改造main.html
<!DOCTYPE html>
<!--导入Shiro的命名空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Shiro 登录认证后主页面</h1>
<br>
登录用户为:<span th:text="${session.user}"></span>
<a href="/logout">退出登录</a>
<br>
<!--如果有admin的角色,则展示这个a链接-->
<a href="/LoginController/userLoginRoles" shiro:hasRole="admin">测试授权-角色验证</a>
<!--如果有user:delete权限,则展示这个a链接-->
<a href="/LoginController/userPermissions" shiro:hasPermission="user:delete">测试授权-权限验证</a>
</body>
  1. 测试
    • 张三有admin角色,user:delete权限,则展示两个 a 标签
    • 李四只有admin角色,没有user:delete权限,则展示 测试授权-角色验证 标签

2、EhCache

EhCache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。可以和大部分Java项目无缝整合。EhCache支持内存和磁盘存储,默认存储在内存中,如内存不够时把缓存数据同步到磁盘中。EhCache支持基于Filter的Cache实现,也支持Gzip压缩算法。

  • EhCache直接在JVM虚拟机中缓存,速度快,效率高
  • EhCache缺点是缓存共享麻烦,集群分布式应用使用不方便

2.1、Shiro整合EhCache

Shiro官方提供了shiro-ehcache,实现了整合EhCache作为Shiro的缓存工具。可以缓存认证执行的Realm方法,减少对数据库的访问,提高认证效率。

  1. 添加依赖
<!--Shiro整合EhCache-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.13.0</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.13.0</version>
</dependency>
  1. 在 resources 下添加配置文件 ehcache/ehcache-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="ehcache" updateCheck="false">
    <!--磁盘的缓存位置-->
    <diskStore path="java.io.tmpdir"/>
    <!--默认缓存-->
    <defaultCache
            maxEntriesLocalHeap="1000"
            eternal="false"
            timeToIdleSeconds="3600"
            timeToLiveSeconds="3600"
            overflowToDisk="false">
    </defaultCache>
    <!--登录认证信息缓存:缓存用户角色权限-->
    <cache name="loginRolePsCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true"/>
</ehcache>
  1. 修改配置类ShiroConfig
/**
 * 配置 SecurityManager
 */
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
    //1.创建defaultWebSecurityManager对象
    DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
    //2.创建加密对象,并设置相关属性
    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
    // 2.1 采用md5加密
    matcher.setHashAlgorithmName("md5");
    // 2.2 迭代加密次数
    matcher.setHashIterations(1024);
    //3.将加密对象存储到CustomerRealm中
    customerRealm.setCredentialsMatcher(matcher);
    //4.将CustomerRealm存储到defaultWebSecurityManager中
    defaultWebSecurityManager.setRealm(customerRealm);
    //4.1 设置RememberMe
    defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
    //5.设置缓存管理器
    defaultWebSecurityManager.setCacheManager(getEhCacheManager());
    //6.返回
    return defaultWebSecurityManager;

}


/**
 * 缓存管理器
 */
public EhCacheManager getEhCacheManager() {
    EhCacheManager ehCacheManager = new EhCacheManager();
    InputStream is = null;

    try {
        is = ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache-shiro.xml");
    } catch (IOException e) {
        e.printStackTrace();
    }
    CacheManager cacheManager = new CacheManager(is);
    ehCacheManager.setCacheManager(cacheManager);
    return ehCacheManager;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/547881.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企业网络日益突出的难题与SD-WAN解决方案

随着企业规模的迅速扩张和数字化转型的深入推进&#xff0c;企业在全球范围内需要实现总部、分支机构、门店、数据中心、云等地点的网络互联、数据传输和应用加速。SD-WAN作为当今主流解决方案&#xff0c;在网络效率、传输质量、灵活性和成本等方面远远超越传统的互联网、专线…

归并排序详解(附代码)

归并排序 数据科学家每天都在处理算法。 然而&#xff0c;数据科学学科作为一个整体已经发展成为一个不涉及复杂算法实现的角色。 尽管如此&#xff0c;从业者仍然可以从建立对算法的理解和知识库中受益。 在本文中&#xff0c;对排序算法归并排序进行了介绍、解释、评估和实…

高温超导量子干涉仪更具实用价值 政策推动行业研制能力提升

高温超导量子干涉仪更具实用价值 政策推动行业研制能力提升 高温超导量子干涉仪&#xff0c;一种采用临界温度在77K以上高温超导材料制造而成的可对磁场微小变化进行测量的仪器&#xff0c;需要工作在液氮环境中。 超导量子干涉仪&#xff08;SQUID&#xff09;&#xff0c;一种…

面试官:为什么忘记密码要重置而不是告诉你原密码?

这是一个挺有意思的面试题,挺简单的,不知道大家平时在重置密码的时候有没有想过这个问题。回答这个问题其实就一句话:因为服务端也不知道你的原密码是什么。如果知道的话,那就是严重的安全风险问题了。 我们这里来简单分析一下。 做过开发的应该都知道,服务端在保存密码到…

CPLD可运行的最高频率是多少

CPLD可运行的最高频率是多少 AG32 内置CPLD的可运行最高频率 AG32 内置CPLD的可运行最高频率 AG32 MCU 的运行最高频率是248M。而CPLD中没有标准的最高频率。 最大能跑多少MHz&#xff0c;取决于cpld 里的设计。 如果是逻辑电路&#xff0c;则不存在时钟的概念。 如果是时序电路…

在vue和 js 、ts 数据中使用 vue-i18n,切换语言环境时,标签文本实时变化

我的项目需要显示两种语言(中文和英文)&#xff0c;并且我想要切换语言时&#xff0c;页面语言环境会随之改变&#xff0c;目前发现&#xff0c;只能在vue中使用$t(‘’)的方式使用&#xff0c;但是这种方式只能在vue中使用&#xff0c;而我的菜单文件是定义在js中&#xff0c;…

直流充电桩与交流充电桩有哪些区别,如何选最靠谱?

在当今快速发展的电动汽车市场&#xff0c;正确选择充电桩成为了车主们面临的重要问题之一。直流充电桩与交流充电桩区到底有什么区别&#xff1f;哪些方面不同&#xff1f;分别适用场景是什么&#xff1f;不同场景应该怎么选&#xff1f;本文一文为您详解。 一、直流充电桩与交…

ObjectMapper的具体介绍与使用

文章目录 声明一、前言二、ObjectMapper与JSONObject比较1、核心主要有三个部分&#xff1a;依赖包不同 2、ObjectMapper使用概述2.1、工程的pom.xml导包信息2.2、创建案例中的测试对象2.3、对象和JSON相互转化2.3.1、测试代码2.3.2、测试结果展示 2.4、集合和JSON像话转化2.4.…

【让自己的U盘变得与众不同】

文章目录 今日座右铭&#xff1a;在心里种花&#xff0c;人生才不会荒芜。 文章目录 文章目录前言一、准备ICO图标二、插入U盘1.点击新建文本文档-输入代码-点击保存2.将代码文本文档名称修改为autorun.inf在这里插入图片描述3.将图标及代码文本文档放入U盘中在这里插入图片描述…

深度残差收缩网络中,使用 Sigmoid 函数的用意在哪?

在深度残差收缩网络中&#xff0c;使用 Sigmoid 函数将输出归一化到 0 和 1 之间的目的是为了限制输出值的范围&#xff0c;并且使得输出可以被解释为概率。这个 Sigmoid 函数的输出可以被看作是一个置信度或者概率的度量&#xff0c;表示某个事件发生的可能性。 在设置阈值时…

财富池指标--通达信主力建仓免费指标公式源码

主力交易一只个股&#xff0c;一般会经过以下几个阶段&#xff1a;建仓、拉升、出货。那么&#xff0c;怎么判断一只股票正处于主力建仓时期呢&#xff1f; 1、从k线图上来看 个股走势图中&#xff0c;连续出现小阳线的k线图&#xff0c;其成交量持续放量&#xff0c;或者在个…

【学习笔记】rt-thread

任务 创建好任务&#xff0c;不管是动态还是静态创建&#xff0c;任务的状态是init &#xff0c;通过start方法来启动任务&#xff1b;线程大小 设置小了&#xff0c;无法正常工作&#xff1f;显示占空间100% 启动过程 TODO 这是编译器特性&#xff1f; 因为RT-Thread使用编…

【QT+QGIS跨平台编译】181:【QGIS+Qt跨平台编译】—【错误处理:找不到_DEBUGA】

点击查看专栏目录 文章目录 一、找不到_DEBUGA二、原因分析三、错误处理 一、找不到_DEBUGA 报错信息&#xff1a; 二、原因分析 采用了非UNICODE&#xff1a; DEFINES - UNICODE没法识别 _DEBUGA 但可以识别 _DEBUG 三、错误处理 修改 _DEBUGA 为 _DEBUG

Android13 开机时间优化

前言 实际生活当中&#xff0c;针对某些应用场景&#xff0c;对Android启动时间要求比较严格&#xff0c;比如车载&#xff0c;车都开出去几公里了&#xff0c;IVI系统还没起来&#xff0c;这就比较尴尬&#xff0c;所以&#xff0c;优化Android启动时间是一项非常重要的工作。…

windows Nginx上部署若依后台管理登录界面之验证码不显示

大多数情况都是本地电脑Nginx部署正常&#xff0c;服务器Nginx部署验证码不显示。如下图 其实是Nginx配置有问题 server {listen 80;//监听端口server_name 域名或者公网ip等;location / {root D:/dist;//前端包文件路径需要修改index index.html; //不用管try_files …

k8s的service为什么不能ping通?——所有的service都不能ping通吗

点击阅读原文 前提&#xff1a;kube-proxy使用iptables模式 Q service能不能ping通&#xff1f; A: 不能&#xff0c;因为k8s的service禁止了icmp协议 B: 不能&#xff0c;因为clusterIP是一个虚拟IP&#xff0c;只是用于配置netfilter规则&#xff0c;不会实际绑定设备&…

深入理解 C++ 中的 KeyFrame 和 KeyFrame*:对象与指针的选择与管理

本文详细讨论了在 C 编程中 KeyFrame 类及其指针 KeyFrame* 的用法、区别与联系。通过探索两者的内存管理、生命周期及使用场景&#xff0c;本文旨在帮助开发者更好地理解何时以及如何选择使用对象或指针&#xff0c;从而提高代码的效率和安全性。 在 C 中&#xff0c;KeyFrame…

求1000以内正整数的平方根(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <math.h>int main() {//初始化变量值&#xff1b;int number 0;int result 0;//提示用户&#xff1b;printf("请输入1000以内求平方根的…

Python 版分布式消息队列 Kafka 实现图片数据传输

1、Kafka 介绍 在使用 Kafka 之前&#xff0c;通常需要先安装和配置 ZooKeeper。ZooKeeper 是 Kafka 的依赖项之一&#xff0c;它用于协调和管理 Kafka 集群的状态。 ZooKeeper 是一个开源的分布式协调服务&#xff0c;它提供了可靠的数据存储和协调机制&#xff0c;用于协调…

超越GPT-4V!马斯克发布Grok-1.5 With Vision

在 Grok-1 开源后不到一个月&#xff0c;xAI 的首个多模态模型就问世了。Grok-1.5V是XAI的第一代多模态模型&#xff0c;除了其强大的文本处理能力之外&#xff0c;Grok现在还能够处理包括文档、图表、图形、屏幕截图和照片在内的各种视觉信息。相信Grok-1.5V将很快提供给现有的…