RuoYi-Vue-Plus(sa-token)

一、介绍

官网: 

Sa-Tokenicon-default.png?t=N7T8https://sa-token.cc/index.html

特性:

  1. 登录与权限认证:支持用户登录和细粒度权限认证。
  2. 会话管理:提供会话创建、维护和销毁功能。
  3. 单点登录:支持单点登录,简化多应用登录流程。
  4. OAuth2.0集成:集成OAuth2.0协议,实现安全授权与认证。
  5. 微服务网关鉴权:确保微服务间的安全访问。
  6. 轻量且易用:功能强大但易于集成和使用。

登录流程简介:

对于一些登录之后才能访问的接口(例如:查询我的账号资料),我们通常的做法是增加一层接口校验:

  • 如果校验通过,则:正常返回数据。
  • 如果校验未通过,则:抛出异常,告知其需要先进行登录。
  1. 用户提交 name + password 参数,调用登录接口。
  2. 登录成功,返回这个用户的 Token 会话凭证。
  3. 用户后续的每次请求,都携带上这个 Token。
  4. 服务器根据 Token 判断此会话是否登录成功。

所谓登录认证,指的就是服务器校验账号密码,为用户颁发 Token 会话凭证的过程,这个 Token 也是我们后续判断会话是否登录的关键所在。

二、集成

注:如果你使用的是 SpringBoot 3.x,只需要将 sa-token-spring-boot-starter 修改为 sa-token-spring-boot3-starter 即可。

1-添加依赖 
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.37.0</version>
</dependency>
2-配置文件编写 

  若依sa-token 配置在yml中,如下:ruoyi-admin/src/main/resources/application.yml

属性讲解:

  •   timeout: 86400  固定有效期,必定一天过期
  •   active-timeout: 1800   临时有效期,30分钟误操作token过期
  • is-concurrent:并发登录,为true时允许一起登录, 为false时新登录挤掉旧登录
    is-read-cookie 是否尝试从cookie里读取token,默认不从cookie中获取,可能会有csrf攻击
# Sa-Token配置
sa-token:
  # token名称 (同时也是cookie名称)
  token-name: Authorization
  # token有效期 设为一天 (必定过期) 单位: 秒
  timeout: 86400
  # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义
  # token最低活跃时间 (指定时间无操作就过期) 单位: 秒
  active-timeout: 1800
  # 允许动态设置 token 有效期
  dynamic-active-timeout: true
  # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
  is-concurrent: true
  # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
  is-share: false
  # 是否尝试从header里读取token
  is-read-header: true
  # 是否尝试从cookie里读取token
  is-read-cookie: false
  # token前缀
  token-prefix: "Bearer"
  # jwt秘钥
  jwt-secret-key: abcdefghijklmnopqrstuvwxyz

三、 常用函数 

1-登录、注销函数
StpUtil.login(Object id);    

只此一句代码,便可以使会话登录成功,实际上,Sa-Token 在背后做了大量的工作,包括但不限于:

1-检查此账号是否之前已有登录;
2-为账号生成 Token 凭证与 Session 会话;
3-记录 Token 活跃时间;
4-通知全局侦听器,xx 账号登录成功;
5-将 Token 注入到请求上下文

 

你暂时不需要完整了解整个登录过程,你只需要记住关键一点:Sa-Token 为这个账号创建了一个Token凭证,且通过 Cookie 上下文返回给了前端。

流程与思路详见:

登录认证 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/use/login-auth

StpUtil.logout();
 

// 当前会话注销登录


StpUtil.isLogin();

// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.checkLogin();// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
2-强制注销
StpUtil.logout(10001);                    // 强制指定账号注销下线 
StpUtil.logout(10001, "PC");              // 强制指定账号指定端注销下线 
StpUtil.logoutByTokenValue("token");      // 强制指定 Token 注销下线 

3-踢人下线
StpUtil.kickout(10001);                    // 将指定账号踢下线 
StpUtil.kickout(10001, "PC");              // 将指定账号指定端踢下线
StpUtil.kickoutByTokenValue("token");      // 将指定 Token 踢下线

强制注销 和 踢人下线 的区别在于:

  • 强制注销等价于对方主动调用了注销方法,再次访问会提示:Token无效。
  • 踢人下线不会清除Token信息,而是将其打上特定标记,再次访问会提示:Token已被踢下线。
 4-会话函数
StpUtil.getLoginId();        // 获取当前会话账号id, 如果未登录,则抛出异常:`NotLoginException`
类似上面

StpUtil.getLoginIdAsString();   // 获取当前会话账号id, 并转化为`String`类型

StpUtil.getLoginIdAsInt();    // 获取当前会话账号id, 并转化为`int`类型

StpUtil.getLoginIdAsLong();   // 获取当前会话账号id, 并转化为`long`类型

StpUtil.getLoginIdDefaultNull();/ 获取当前会话账号id, 如果未登录,则返回 null
StpUtil.getLoginId(T defaultValue);// 获取当前会话账号id, 如果未登录,则返回默认值 (`defaultValue`可以为任意类型)
5-Token查询
StpUtil.getTokenValue();// 获取当前会话的 token 值
StpUtil.getTokenName();// 获取当前`StpLogic`的 token 名称
StpUtil.getLoginIdByToken(String tokenValue);
// 获取指定 token 对应的账号id,如果未登录,则返回 null
StpUtil.getTokenTimeout();// 获取当前会话剩余有效期(单位:s,返回-1代表永久有效)
StpUtil.getTokenInfo();// 获取当前会话的 token 信息参数

关于token参数详解:

{
    "code": 200,
    "msg": "ok",
    "data": {
        "tokenName": "satoken",           // token名称
        "tokenValue": "e67b99f1-3d7a-4a8d-bb2f-e888a0805633",      // token值
        "isLogin": true,                  // 此token是否已经登录
        "loginId": "10001",               // 此token对应的LoginId,未登录时为null
        "loginType": "login",              // 账号类型标识
        "tokenTimeout": 2591977,          // token剩余有效期 (单位: 秒)
        "sessionTimeout": 2591977,        // Account-Session剩余有效时间 (单位: 秒)
        "tokenSessionTimeout": -2,        // Token-Session剩余有效时间 (单位: 秒) (-2表示系统中不存在这个缓存)
        "tokenActiveTimeout": -1,         // token 距离被冻结还剩的时间 (单位: 秒)
        "loginDevice": "default-device"   // 登录设备类型 
    },
}

 四、权限

自行查看 api接口

权限认证 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/use/jur-auth

5-注解鉴权

注解鉴权 —— 优雅的将鉴权与业务代码分离!

  • @SaCheckLogin: 登录校验 —— 只有登录之后才能进入该方法。
  • @SaCheckRole("admin"): 角色校验 —— 必须具有指定角色标识才能进入该方法。
  • @SaCheckPermission("user:add"): 权限校验 —— 必须具有指定权限才能进入该方法。
  • @SaCheckSafe: 二级认证校验 —— 必须二级认证之后才能进入该方法。
  • @SaCheckBasic: HttpBasic校验 —— 只有通过 Basic 认证后才能进入该方法。
  • @SaIgnore:忽略校验 —— 表示被修饰的方法或类无需进行注解鉴权和路由拦截器鉴权。
  • @SaCheckDisable("comment"):账号服务封禁校验 —— 校验当前账号指定服务是否被封禁。

你必须手动将 Sa-Token 的全局拦截器注册到你项目中 

官网文档:

路由拦截鉴权 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/use/route-check?id=_1%E3%80%81%E6%B3%A8%E5%86%8C-sa-token-%E8%B7%AF%E7%94%B1%E6%8B%A6%E6%88%AA%E5%99%A8

下面是若依中的实现: 

@RequiredArgsConstructor
@Slf4j
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {

    private final SecurityProperties securityProperties;

    /**
     * 注册sa-token的拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册路由拦截器,自定义验证规则
        registry.addInterceptor(new SaInterceptor(handler -> {
            AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class);
            // 登录验证 -- 排除多个路径
            SaRouter
                // 获取所有的
                .match(allUrlHandler.getUrls())
                // 对未排除的路径进行检查
                .check(() -> {
                    // 检查是否登录 是否有token
                    StpUtil.checkLogin();

                    // 有效率影响 用于临时测试
                    // if (log.isDebugEnabled()) {
                    //     log.info("剩余有效时间: {}", StpUtil.getTokenTimeout());
                    //     log.info("临时有效时间: {}", StpUtil.getTokenActiveTimeout());
                    // }

                });
        })).addPathPatterns("/**")
            // 排除不需要拦截的路径
            .excludePathPatterns(securityProperties.getExcludes());
    }

    @Bean
    public StpLogic getStpLogicJwt() {
        // Sa-Token 整合 jwt (简单模式)
        return new StpLogicJwtForSimple();
    }

    /**
     * 权限接口实现(使用bean注入方便用户替换)
     */
    @Bean
    public StpInterface stpInterface() {
        return new SaPermissionImpl();
    }

    /**
     * 自定义dao层存储
     */
    @Bean
    public SaTokenDao saTokenDao() {
        return new PlusSaTokenDao();
    }

}

五、session 会话 

在 Sa-Token 中,Session 分为三种,分别是:

  • Account-Session: 指的是框架为每个 账号id 分配的 Session
  • Token-Session: 指的是框架为每个 token 分配的 Session
  • Custom-Session: 指的是以一个 特定的值 作为SessionId,来分配的 Session
// 在登录时缓存 user 对象 
StpUtil.getSession().set("user", user);

// 然后我们就可以在任意处使用这个 user 对象
SysUser user = (SysUser) StpUtil.getSession().get("user");

1-Account-Session 绑定当前用户id ,api如下
// 获取当前账号 id 的 Account-Session (必须是登录后才能调用)
StpUtil.getSession();

// 获取当前账号 id 的 Account-Session, 并决定在 Session 尚未创建时,是否新建并返回
StpUtil.getSession(true);

// 获取账号 id 为 10001 的 Account-Session
StpUtil.getSessionByLoginId(10001);

// 获取账号 id 为 10001 的 Account-Session, 并决定在 Session 尚未创建时,是否新建并返回
StpUtil.getSessionByLoginId(10001, true);

// 获取 SessionId 为 xxxx-xxxx 的 Account-Session, 在 Session 尚未创建时, 返回 null 
StpUtil.getSessionBySessionId("xxxx-xxxx");
 2- Token-Session 绑定当前token的信息
// 获取当前 Token 的 Token-Session 对象
StpUtil.getTokenSession();

// 获取指定 Token 的 Token-Session 对象
StpUtil.getTokenSessionByToken(token);
3-Custom-Session  自定义sessionid

比如 ,下面goods-10001是某个商品的id

// 查询指定key的Session是否存在
SaSessionCustomUtil.isExists("goods-10001");

// 获取指定key的Session,如果没有,则新建并返回
SaSessionCustomUtil.getSessionById("goods-10001");

// 获取指定key的Session,如果没有,第二个参数决定是否新建并返回  
SaSessionCustomUtil.getSessionById("goods-10001", false);   

// 删除指定key的Session
SaSessionCustomUtil.deleteSessionById("goods-10001");

 官网还提供一些 session 读写的api ,自行查看

Session会话 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/use/session?id=%E5%9C%A8-session-%E4%B8%8A%E5%AD%98%E5%8F%96%E5%80%BC

六、sa-token 登录拦截器

1、路由权限拦截器

类路径:com.ruoyi.framework.config.SaTokenConfig,实现WebMvcConfigurer 接口

1-通过 registry.addInterceptor(new SaInterceptor(handler -> { } 添加 SaInterceptor 拦截器

2-在拦截器中可以自定义登录、角色、权限的校验

  • 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
  • 角色校验 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证 SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin")); 权限校验 -- 不同模块校验不同权限 SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));

3- 排除不需要拦截的路径(该配置在 ruoyi-admin 模块的yml中配置
            .excludePathPatterns(securityProperties.getExcludes());

其他注入  

  • 通过 getStpLogicJwt 方法, 注入 tpLogic 类是为了整合Jwt
  • 通过 stpInterface方法,注入 StpInterface 接口,手动去实现
  • 注入SaTokenDao ,实现对redis对sotoken的读写
    
@RequiredArgsConstructor
@Slf4j
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {

    private final SecurityProperties securityProperties;

    /**
     * 注册sa-token的拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册路由拦截器,自定义验证规则
        registry.addInterceptor(new SaInterceptor(handler -> {
            AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class);
            // 登录验证 -- 排除多个路径
            SaRouter
                // 获取所有的
                .match(allUrlHandler.getUrls())
                // 对未排除的路径进行检查
                .check(() -> {
                    // 检查是否登录 是否有token
                    StpUtil.checkLogin();

                    // 有效率影响 用于临时测试
                    // if (log.isDebugEnabled()) {
                    //     log.info("剩余有效时间: {}", StpUtil.getTokenTimeout());
                    //     log.info("临时有效时间: {}", StpUtil.getTokenActiveTimeout());
                    // }

                });
        })).addPathPatterns("/**")
            // 排除不需要拦截的路径
            .excludePathPatterns(securityProperties.getExcludes());
    }

    @Bean
    public StpLogic getStpLogicJwt() {
        // Sa-Token 整合 jwt (简单模式)
        return new StpLogicJwtForSimple();
    }

    /**
     * 权限接口实现(使用bean注入方便用户替换)
     */
    @Bean
    public StpInterface stpInterface() {
        return new SaPermissionImpl();
    }

    /**
     * 自定义dao层存储
       * PlusSaTokenDao  Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一)
     */
    @Bean
    public SaTokenDao saTokenDao() {
        return new PlusSaTokenDao();
    }

}
2- saTokenDao

     上面配置中,自定义dao层存储,注入 PlusSaTokenDao 作为 Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一) ,
     


    @Bean
    public SaTokenDao saTokenDao() {
        return new PlusSaTokenDao();
    }

若果不去自己实现sotoken的DAO层接口,框架默认会基于内存区存储,如下 SaTokenDaoDefaultImpl 类实现 SaTokenDao

public class SaTokenDaoDefaultImpl implements SaTokenDao {
    public Map<String, Object> dataMap = new ConcurrentHashMap();
    public Map<String, Long> expireMap = new ConcurrentHashMap();

.......
3-sotoken Jwt 介绍

JWT就是上述流程当中token的一种具体实现方式,其全称是JSON Web Token

通俗地说,JWT的本质就是一个字符串,它是将用户信息保存到一个Json字符串中,然后进行编码后得到一个JWT token,并且这个JWT token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为Json对象传输。JWT的详细博文如下:

JWT详解-CSDN博客文章浏览阅读10w+次,点赞927次,收藏4.6k次。本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:JWT详解JWT简介1.什么是JWT在介绍JWT之前,我们先来回顾一下利用token进行用户身份验证的流程:客户端使用用户名和密码请求登录服务端收到请求,验证用户名和密码验证成功后,服务端会签发一个token,再把这个token返回给客户端客户端收到token后可以把它存储起来,比如放到cookie中客户端每次向服务端请求资源时需要携带服务端签发的token,可以在cookie或者header中携带服务端收到请求,然后去验证客户端请_jwt详解https://blog.csdn.net/weixin_45070175/article/details/118559272

 

1-集成

依赖:ruoyi-common/pom.xml 中

        <!-- Sa-Token 整合 jwt -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-jwt</artifactId>
        </dependency>

 配置秘钥 : 上面 ruoyi-amin配置文件sotoken中配置

# Sa-Token配置
sa-token:
  # jwt秘钥
  jwt-secret-key: abcdefghijklmnopqrstuvwxyz

 com.ruoyi.framework.config.SaTokenConfig 类中注入

 @Bean
    public StpLogic getStpLogicJwt() {
        // Sa-Token 整合 jwt (简单模式)
        return new StpLogicJwtForSimple();
    }

整合文档参考:

和 jwt 集成 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/plugin/jwt-extend

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

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

相关文章

基于el-table实现行内增删改

实现效果&#xff1a; 核心代码&#xff1a; <el-table :data"items"style"width: 100%;margin-top: 16px"border:key"randomKey"><el-table-column label"计划名称"property"name"><template slot-scope&q…

雪里温柔,水边明秀,不及Java 抽象类 和 Object类

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

Linux环境基础开发工具使用——yum and vim

本篇将会介绍平时在Linux中开发常用到的一些工具&#xff0c;其中包括&#xff1a;软件包管理器 — yum&#xff0c;Liunx中的开发工具。具体的介绍了 yum 的相关操作以及 yum 源&#xff0c;同时还介绍了 windows与虚拟机如何进行的关联。然后对Liunx中的开发工具进行了详细的…

集合(下)Map集合的使用

文章目录 前言一、Map接口二、Map接口的实现类 1.HashMap类2.TreeMap类总结 前言 Map集合没有继承Collection接口&#xff0c;不能像List集合和Set集合那样直接使用Collection接口的方法。Map集合其自身通过以key到value的映射关系实现的集合&#xff0c;也有相应的许多方法。类…

超详细SpringMVC源码剖析

整体流程图 1.自定义视图(63~66) 视图解析过程 1.先到DispatcherServlet中央控制器, 根据视图解析的 优先级 执行对应的 视图解析器 Nullable protected View resolveViewName(String viewName, Nullable Map<String, Object> model,Locale locale, HttpServletReque…

【C语言】【Leetcode】70. 爬楼梯

文章目录 题目思路&#xff1a;简单递归 > 动态规划 题目 链接: link 思路&#xff1a;简单递归 > 动态规划 这题类似于斐波那契数列的算法&#xff0c;结果其实就是到达前一步和到达前两步的方法之和&#xff0c;一直递归到n1和n2时就行了&#xff0c;但是这种算法有个…

Fiddler抓包工具之fiddler的常用快捷键

一、常用三个快捷键 ctrlX :清空所有记录 CtrlF&#xff1a;查找 F12&#xff1a;启动或者停止抓包 使用 QuickExec Fiddler2 成了网页调试必备的工具&#xff0c;抓包看数据。Fiddler2自带命令行控制。 fiddler 命令行快捷键&#xff1a;ctrl q &#xff0c;然后 输入 help…

linux C:变量、运算符

linux C 文章目录 变量运算符 一、变量 [存储类型] 数据类型 标识符 值 标识符&#xff1a;由数字、字母、下划线组成的序列&#xff0c;不能以数字开头。 数据类型&#xff1a;基本数据类型构造类型 存储类型&#xff1a;auto static…

碳课堂|什么是碳资产?企业如何进行碳资产管理?

碳资产是绿色资产的重要类别&#xff0c;在全球气候变化日益严峻的背景下备受关注。在“双碳”目标下&#xff0c;碳资产管理是企业层面实现碳减排目标和低碳转型的关键。 一、什么是碳资产&#xff1f; 碳资产是以碳减排为基础的资产&#xff0c;是企业为了积极应对气候变化&…

idea中Git项目遇到“Filename too long”错误 与 配置Git的ssh证书

一&#xff1a;“Filename too long”问题解决办法 错误信息&#xff1a; fatal: cannot create directory at xxxx: Filename too long warning: Clone succeeded, but checkout failed. You can inspect what was checked out with git status and retry with git restore …

java算法第32天 | 贪心算法 part02 ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机II 本题中理解利润拆分是关键点&#xff01; 不要整块的去看&#xff0c;而是把整体利润拆为每天的利润。假如第 0 天买入&#xff0c;第 3 天卖出&#xff0c;那么利润为&#xff1a;prices[3] - prices[0]。 相当于(prices[3] - prices[2]) (prices[…

[医学分割大模型系列] (3) SAM-Med3D 分割大模型详解

[医学分割大模型系列] -3- SAM-Med3D 分割大模型解析 1. 特点2. 背景3. 训练数据集3.1 数据集收集3.2 数据清洗3.3 模型微调数据集 4. 模型结构4.1 3D Image Encoder4.2 3D Prompt Encoder4.3 3D mask Decoder4.4 模型权重 5. 评估5.1 评估数据集5.2 Quantitative Evaluation5.…

李宏毅【生成式AI导论 2024】第1讲:生成式AI是什么?

什么是人工智能? 人工智慧可以说是一个目标,是一个我们想要达到的目标。它不是一个单一的技术,并没有哪一个技术叫做人工智慧,人工智慧是一个目标。 什么是生成式人工智能? 生成式人工智慧是要机器产生复杂而有结构的物件。比如说文章,文章也有一连串的文字所构成的。比…

[蓝桥杯 2023 省 A] 颜色平衡树:从零开始理解树上莫队 一颗颜色平衡树引发的惨案

十四是一名生物工程的学生&#xff0c;他已经7年没碰过信息学竞赛了&#xff0c;有一天他走在蓝桥上看见了一颗漂亮的颜色平衡树&#xff1a; ​​​​​​​[蓝桥杯 2023 省 A] 颜色平衡树 - 洛谷 十四想用暴力解决问题&#xff0c;他想枚举每个节点&#xff0c;每个节点代表…

死锁-写一个死锁的例子

死锁-写一个死锁的例子 什么是死锁死锁产生的条件如何避免死锁死锁预防死锁避免死锁检测死锁解除鸵鸟策略 手写一个死锁的例子 https://blog.51cto.com/u_16213642/8352155 什么是死锁 在两个或者多个并发进程中&#xff0c;如果每个进程持有某种资源而又等待其它进程释放它或…

代码随想录算法训练营第三十五天|860. 柠檬水找零,406. 根据身高重建队列,452. 用最少数量的箭引爆气球

860. 柠檬水找零 题目 在柠檬水摊上&#xff0c;每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品&#xff0c;&#xff08;按账单 bills 支付的顺序&#xff09;一次购买一杯。 每位顾客只买一杯柠檬水&#xff0c;然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾…

C语言例4-8:格式字符c的使用例子

代码如下&#xff1a; //格式字符c的使用例子 #include<stdio.h> int main(void) {char c A;int i 65;printf("c%c,%5c,%d\n",c,c,c);printf("i%d,%c\n",i,i);return 0; } 结果如下&#xff1a;

22.WEB渗透测试-BurpSuite(一)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;21.WEB渗透测试-HTTP协议&#xff08;下&#xff09;-CSDN博客 工具的使用需要先搭建靶场…

水牛社:宝妈副业,不仅赚钱更成长:一段充实之旅

大家好&#xff01;作为一名90后的全职宝妈&#xff0c;今天非常荣幸能够与大家分享我的互联网赚钱经验。趁着宝宝午睡的宝贵时光&#xff0c;我抓紧写下了这篇文章&#xff0c;虽时间紧凑&#xff0c;但我会力求内容清晰明了。 大约从2022年4月开始&#xff0c;我踏上了互联网…

天工AI搜索引擎

相信正在看autosar架构相关内容的人来说&#xff0c;对于autosar相关知识或者配置项的生涩知识点可谓是苦之久矣&#xff0c;这个时候一个好的搜索引擎能带来的帮助太大了&#xff0c;不管是平时百度还是看文档都需要大量的时间去检索自己真正想知道的信息&#xff0c;偶然间发…
最新文章