Casbin——Java版本(笔记)

news2024/11/21 2:36:22

文章目录

  • 一、Casbin 是什么?
  • 二、快速开始
    • 2.1 载入配置
    • 2.2 如何判断权限
    • 2.3 model.conf
      • 2.3.1 基本格式
      • 2.3.2 SpringBoot下的使用
      • 2.3.3 匹配的函数
        • 内置函数
        • 自定义函数
      • 2.3.4 基于角色的访问控制
        • 角色的层次
        • 区分用户和角色
        • 隐式角色权限
        • 域内RBAC
        • 角色与函数
      • 2.3.5 优先级模型
        • 通过隐式优先级加载策略
        • 通过显式优先级加载策略
        • 基于角色和用户层次结构以优先级加载策略
      • 2.3.6 超级管理员
    • 2.4 存储操作
      • 2.4.1 Model存储
      • 2.4.2 Policy存储
        • 从 CSV 文件载入策略
        • 数据库存储格式
        • 适配器
        • 政策子集加载
  • 三、扩充功能部分
  • 四、API部分
  • 五、其他
    • 多数据源
    • 异常设定
  • 附录

一、Casbin 是什么?

也被成为PERM模型: subject(sub 访问实体),object(obj访问的资源)和action(act访问方法)eft(策略结果,一般为空 默认指定allow)还可以定义为deny
Casbin 可以:

  • 支持自定义请求的格式,默认的请求格式为{subject, object, action}。
  • 具有访问控制模型model和策略policy两个核心概念。
  • 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。
  • 支持内置的超级用户 例如:root 或 administrator。超级用户可以执行任何操作而无需显式的权限声明。
  • 支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar 可以映射到 /foo*

Casbin 不能:

  • 身份认证 authentication(即验证用户的用户名和密码),Casbin 只负责访问控制。应该有其他专门的组件负责身份认证,然后由 Casbin 进行访问控制,二者是相互配合的关系。

  • 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系

RBAC(Role-Based Access Control)即:基于角色的权限控制。通过角色关联用户,角色关联权限的方式间接赋予用户权限。

二、快速开始

<-- https://mvnrepository.com/artisfact/org.casbin/jcasbin -->
<dependency>
    <groupId>org.casbin</groupId>
    <artifactId>jcasbin</artifactId>
    <version>1.x.y</version>
</dependency>

SpringBoot版

	<dependency>
		<groupId>org.casbin</groupId>
		<artifactId>casbin-spring-boot-starter</artifactId>
	</dependency>

Casbin 拥有两个重要的文件

  • model.conf:存储了访问模型
  • policy.csv:存储了特定的用户权限配置

2.1 载入配置

  1. 使用时,如下方式载入
import org.casbin.jcasbin.main.Enforcer;

Enforcer e = new Enforcer("path/to/model.conf", "path/to/policy.csv");
  1. 通过yml文件载入
casbin:
  #是否开启Casbin,默认开启
  enableCasbin: true
  #是否使用线程同步的Enforcer,默认false
  useSyncedEnforcer: false
  #是否开启策略自动保存,如适配器支持该功能,默认开启
  autoSave: true
  #存储类型[file,jdbc],目前支持的jdbc数据库[mysql(mariadb),h2,oracle,postgresql,db2]
  #欢迎编写并提交您所使用的jdbc适配器,参见:org.casbin.adapter.OracleAdapter
  #jdbc适配器将主动寻找您在spring.datasource配置的数据源信息
  #默认使用jdbc,并使用内置h2数据库进行内存存储
  storeType: jdbc
  #当使用jdbc时,定制化数据库表名,默认表名是casbin_rule
  tableName: casbin_rule
  #数据源初始化策略[create(自动创建数据表,如已创建则不再进行初始化),never(始终不进行初始化)]
  initializeSchema: create
  #本地模型配置文件地址,约定默认读取位置:classpath:casbin/model.conf
  model: classpath:casbin/model.conf
  #如默认位置未找到模型配置文件,且casbin.model未正确设置,则使用内置默认rbac模型,默认生效
  useDefaultModelIfModelNotSetting: true
  #本地策略配置文件地址,约定默认读取位置:classpath:casbin/policy.csv
  #如默认位置未找到配置文件,将会抛出异常
  #该配置项仅在casbin.storeType设定为file时生效
  policy: classpath:casbin/policy.csv
  #是否开启CasbinWatcher机制,默认不开启
  #如开启该机制,则casbin.storeType必须为jdbc,否则该配置无效
  enableWatcher: false
  #CasbinWatcher通知方式,默认使用Redis进行通知同步,暂时仅支持Redis
  #开启Watcher后需手动添加spring-boot-starter-data-redis依赖
  watcherType: redis
  #异常抛出时机控制
  exception:
    ... 详见附表-异常设定

policy因为比较多,一般存储在数据库中,我们这里先放在csv中作为简单的开始。

使用如下配置

casbin:
  enableCasbin: true
  storeType: file
  model: classpath:casbin/model.conf
  useDefaultModelIfModelNotSetting: true
  policy: classpath:casbin/policy.csv

2.2 如何判断权限

我们通过对请求用enforce进行判断

String sub = "alice"; // 想要访问资源的用户
String obj = "data1"; // 将要被访问的资源
String act = "read"; // 用户对资源进行的操作
// 这个是默认格式,我们可以基于自己想要的在model.conf中修改
// 如:enforce(sub, obj, act,act2)
if (e.enforce(sub, obj, act) == true) {
    // 允许alice读取data1
} else {
    // 拒绝请求,抛出异常
}

2.3 model.conf

可以参考官网-支持的Models

2.3.1 基本格式

# 请求定义 
# 它明确了 e.Enforce(...) 函数中参数的含义。
[request_definition]
r = sub, obj, act

# sub, obj, act 表示经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action)。 
# 比如:user, home/detail, post
# 但是, 你可以自定义你自己的请求表单, 如果不需要指定特定资源,则可以这样定义 sub,act,或者如果有两个访问实体, 则为 sub,sub2,obj,act。



# 策略定义 
# 是策略部分的定义,由它定义我们policy.csv中读出的权限格式
# 如下是两种策略 p 和 p2
[policy_definition]
p = sub, obj, act
p2 = sub, act

# 是策略效果的定义。 
# 它确定如果多项政策规则与请求相符,是否应批准访问请求。 
#  p.eft 代表p的决策结果(是否匹配)
# 如下,代表存在一个匹配的策略规则就通过。
[policy_effect]
e = some(where (p.eft == allow))

# 相反
# 如下,代表存在一个不匹配就不通过。
[policy_effect]
e = !some(where (p.eft == deny)) 



# 请求和策略的匹配规则
# 它定义了如何根据请求评估策略规则
# 也就是 p.eft 的值
# 如下就是要求完全一致,才可以访问
# 除了与或非,也支持 in 判断是否再数组中,eval执行CSV中的判断语句
[matchers]
m = (r.sub == p.sub && r.obj == p.obj && r.act == p.act)

我们可以将r.sub.Age > 18这类语句放入eval中

CSV

p, r.sub.Age > 18, /data1, read
p, r.sub.Age < 60, /data2, write

2.3.2 SpringBoot下的使用

为了方便,我们这里引入一个依赖

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

我们准备如下权限

policy.csv

p,user,post
p2,admin,/info,get

model.conf

[request_definition]
r = sub, act
r2 = sub, obj, act

[policy_definition]
p = sub, act
p2 = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))
e2 = some(where (p.eft == allow))


[matchers]
m = (r.sub == p.sub && r.act == p.act)
m2 = (r2.sub == p2.sub && r2.obj == p2.obj && r2.act == p2.act)

注意,这里effect e2需要用p,而不是p2
在这里插入图片描述

yml

casbin:
  enableCasbin: true

  model: classpath:casbin/model.conf
  useDefaultModelIfModelNotSetting: true
  policy: classpath:casbin/policy.csv

Java


package cn.aos.aoscasbin.controller;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.casbin.jcasbin.main.Enforcer;
import org.casbin.jcasbin.util.EnforceContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
@Slf4j
@AllArgsConstructor
public class test {

    private final Enforcer enforcer;

    @GetMapping
    public void test(){
        log.info("{}",enforcer.enforce("user","post"));
        log.info("{}",enforcer.enforce("admin","post"));
        // 使用第二个匹配器
        EnforceContext enforceContext = new EnforceContext("2");
        log.info("{}",enforcer.enforce(enforceContext,"admin","/info","get"));
        log.info("{}",enforcer.enforce(enforceContext,"user","/info","post"));
        return;
    }
}

在这里插入图片描述

另外,请注意,EnforceContext 生成后是统一指定第几个匹配,我们仍然可以通过提供的set方法,单独设置,指定想要e、p、r、m。

2.3.3 匹配的函数

内置函数

详情可自行查看-函数

下列函数都需要两个参数

  • keyGet and keyGet2 将返回匹配通配符(*)的字符串,如果没有匹配返回 “”
  • 其余函数将返回两个参数是否匹配
    在这里插入图片描述

我们只需要直接使用即可(在conf中)。

自定义函数


	public class CustomFunc extends CustomFunction {
        @Override
        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
            String key1 = FunctionUtils.getStringValue(arg1, env);
            String key2 = FunctionUtils.getStringValue(arg2, env);
            if (key1.equals("/alice_data2/myid/using/res_id") && key2.equals("/alice_data/:resource")) {
                return AviatorBoolean.valueOf(true);
            } else if (key1.equals("/alice_data2/myid/using/res_id") && key2.equals("/alice_data2/:id/using/:resId")) {
                return AviatorBoolean.valueOf(true);
            } else {
                return AviatorBoolean.valueOf(false);
            }
        }

        @Override
        public String getName() {
            return "keyMatchCustom";
        }
    }

   CustomFunc customFunc = new CustomFunc();
   /**
    * @param 注册函数名称
    * @param 函数
    * */
   enforcer.addFunction(customFunc.getName(), customFunc);

注意,只有通过addFunction注册后,才能在对应的conf中直接使用

2.3.4 基于角色的访问控制

# 角色定义 
# 是RBAC角色继承关系的定义,Casbin 支持 RBAC 系统的多个实例。
# 例如, 用户可以具有角色及其继承关系, 资源也可以具有角色及其继承关系。
# 这两个 RBAC 系统不会互相干扰。
[role_definition]
g = _, _
g2 = _, _

上述角色定义表明, g 是一个 RBAC系统, g2 是另一个 RBAC 系统。
_, _表示角色继承关系的前项和后项,即前项继承后项角色的权限。

我们在CSV中
g,用户,角色(代表用户为该角色)
g,角色1,角色2(代表角色1继承角色2)


一般来讲,如果需要进行角色和用户的绑定,直接使用g即可。

当需要表示角色(或者组)与用户和资源的绑定关系时,可以使用 g 和 g2 这样的表现形式。

在Casbin里,我们以policy表示中实际的用户角色映射关系 (或是资源-角色映射关系),例如:

这里时 alice 有 data2_admin的权限

p, data2_admin, data2, read
g, alice, data2_admin

我们通过 g()来判断对应的角色,接下来再用p去查询角色权限

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

角色用户资源绑定关系,可以如下写法

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _
g2 = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act

角色的层次

Casbin 的 RBAC 支持 RBAC1 的角色层次结构功能

如果 alice具有role1, role1具有role2,则 alice 也将拥有 role2 并继承其权限。因此, 此时role1的层次结构级别为2。

对于Casbin中的内置角色管理器, 可以指定最大层次结构级别。 默认值为10。 这意味着终端用户 alice 只能继承10个级别的角色。

区分用户和角色

在RBAC中,Casbin不对用户和角色进行区分。 它们都被视为字符串。

  • 如果你只使用单层的RBAC模型(角色不会成为另一个角色的成员)。

可以使用 e.GetAllSubjects() 获取所有用户,e.GetAllRoles() 获取所有角色。

它们会为规则 g, u, r 分别列出所有的 u 和 r。

  • 如果你在使用多层RBAC(带有角色继承),并且你的应用没有记录下一个名字(字符串)对应的是用户还是角色,或者你将用户和角色用相同的名字命名。

那么你可以可以给角色加上像 role::admin 的前缀再传递到Casbin中。

由此可以通过查看前缀来区分用户和角色。

隐式角色权限

当用户通过RBAC层次结构继承角色或权限,而不是直接在策略规则中分配它们时,我们将这种类型的分配称为 implicit。

也就是我们在代码中添加的,而不是在CSV中添加的。

比如(详情请自行查阅API)

boolean added = e.addGroupingPolicy("group1", "data2_admin");

// 或者
String[][] groupingRules = {
    {"ham", "data4_admin"},
    {"jack", "data5_admin"}
};
boolean areRulesAdded = e.addGroupingPolicies(groupingRules);

此外,带有name就是我们可以定义g,p(ptype)这种不同的数据


要查询这种隐式关系,需要使用以下两个api:
GetImplicitRolesForUser()以及 GetImplicitPermissionsForUser() 替代GetRolesForUser() 以及GetPermissionsForUser()

域内RBAC

我们可以将角色划分在不同域中(即不同应用、系统下)

[role_definition]
g = _, _, _

如此我们进一步划分了角色作用范围

p, admin, tenant1, data1, read
p, admin, tenant2, data2, read

g, alice, admin, tenant1
g, alice, user, tenant2
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act

我们在g()中对比了g与r域(dom)的关系

如果可能,还需要在后面对比 p和r的域对应关系r.dom == p.dom

角色与函数

如下,与之前的很类似
ptype(g,p这些),绑定的名称,实现

	// 自定义函数	
		enforcer.addNamedMatchingFunc("g", "", new BiPredicate<String, String>() {
            @Override
            public boolean test(String s, String s2) {
                return false;
            }
        });
        // 域匹配与自定义函数
        enforcer.addNamedDomainMatchingFunc("g","", new BiPredicate<String, String>() {
            @Override
            public boolean test(String s, String s2) {
                return false;
            }
        });
        

2.3.5 优先级模型

通过隐式优先级加载策略

顺序决定了策略的优先级,策略出现的越早优先级就越高,也就是使用了默认顺序

[policy_effect]
e = priority(p.eft) || deny

通过显式优先级加载策略

策略定义中的优先级令牌名称必须是“优先级”较小的优先级值将具有较高的优先级

如果优先级有非数字字符,它将是被排在最后,而不是导致报错。

现在,明确的优先级仅支持 添加策略 & 添加策略,如果 升级策略 被调用,那么不应该改变优先级属性。

[request_definition]
r = sub, obj, act

[policy_definition]
p = priority, sub, obj, act, eft

[role_definition]
g = _, _

[policy_effect]
e = priority(p.eft) || deny

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
p, 10, data1_deny_group, data1, read, deny
p, 10, data1_deny_group, data1, write, deny
p, 10, data2_allow_group, data2, read, allow
p, 10, data2_allow_group, data2, write, allow


p, 1, alice, data1, write, allow
p, 1, alice, data1, read, allow
p, 1, bob, data2, read, deny

g, bob, data2_allow_group
g, alice, data1_deny_group

基于角色和用户层次结构以优先级加载策略

角色和用户的继承结构只能是多棵树,而不是图。

如果一个用户有多个角色,您必须确保用户在不同树上有相同的等级

如果两种角色具有相同的等级,那么出现早的策略(相应的角色)就显得更加优先。

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act, eft

[role_definition]
g = _, _

[policy_effect]
e = subjectPriority(p.eft) || deny

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act 

subject -> sub

p, root, data1, read, deny
p, admin, data1, read, deny

p, editor, data1, read, deny
p, subscriber, data1, read, deny

p, jane, data1, read, allow
p, alice, data1, read, allow

g, admin, root

g, editor, admin
g, subscriber, admin

g, jane, editor
g, alice, subscriber 

在这里插入图片描述

2.3.6 超级管理员

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"

它说明了对于定义的 request_definition, policy_definition, policy_effect 和 matcher, Casbin 判断如果请求可以匹配的上策略,或者更重要的,如果 sub 是超级用户的话。

一旦判决正确,就允许授权,而且用户有权做一切。

就像Linux系统的root一样,用户被授权为 root, 我们就有访问所有文件和设置的权限。 因此,如果我们想要 sub 能够完全访问整个系统。 我们可以让它成为超级管理员,然后 sub 才有权做一切。

2.4 存储操作

2.4.1 Model存储

与 policy 不同,model 只能加载,不能保存。 因为作者认为 model 不是动态组件,不应该在运行时进行修改,所以没有实现一个 API 来将 model 保存到存储中。

因此只能从

  • 从 .CONF 文件中加载 model
  • 从代码加载 model
  • 从字符串加载的 model

2.4.2 Policy存储

从 CSV 文件载入策略

这是我们最开始的方式。
在这里插入图片描述

数据库存储格式

要使用数据库存储,请参考最开始的yml配置
我们可以手动为其添加配置,也可以用enforce添加
在这里插入图片描述

在这里插入图片描述

  • id: 只存在于数据库中作为主键。 不作为 Casbin策略的一部分。它生成的方式取决于特定的适配器

  • ptype: 它对应 p, g, g2, 等等。

  • v0-v5: 列名称没有特定的含义, 并对应 策略csv 中的值。 列数取决于自定义的数量。 理论上,可以有无限的列数。 但通常在适配器中只有 6 列。 如果您觉得还不够,请向相应的适配器仓库提交问题

适配器

适配器更换、指定此处省略。详情请翻看-适配器

在Casbin中,策略存储作为adapter(Casbin的中间件) 实现。

Casbin用户可以使用adapter从存储中加载策略规则 (aka LoadPolicy()) 或者将策略规则保存到其中 (aka SavePolicy())。

为了保持代码轻量级,作者没有把adapter代码放在主库中。

在这里插入图片描述

如果使用显式或隐式adapter调用casbin.NewEnforcer(),策略将自动加载。
可以调用e.LoadPolicy() 来从存储中重新加载策略规则。
如果adapter不支持Auto-Save特性,则在添加或删除策略时不能将策略规则自动保存回存储器。 你必须手动调用 SavePolicy() 来保存所有的策略规则

顺便说一下,我们可以看到,我们引入的Spring Boot的Casbin依赖,用的是JDBC Adapter
在这里插入图片描述

政策子集加载

一些adapter支持过滤策略管理。 这意味着Casbin加载的策略是基于给定过滤器的存储策略的子集。 当解析整个策略成为性能瓶颈时,这将会允许在大型多租户环境中有效地执行策略。

要使用支持的adapter处理过滤后的策略,只需调用 LoadFilteredPolicy 方法。 过滤器参数的有效格式取决于所用的适配器。 为了防止意外数据丢失,当策略已经加载, SavePolicy 方法会被禁用
(也就是担心,过滤的数据覆盖了原数据)

我们如果要过滤,可以如下写法

      enforcer.loadFilteredPolicy(new FilteredAdapter.Filter());

当然这是一个空的过滤器,filter类如下,我们需要设置过滤策略

	public static class Filter {
        public String[] p;
        public String[] g;

        public Filter() {
        }
    }

请注意,笔者是在数据库模式下使用。非数据库模式下(至少笔者使用的这一依赖)不可以用。
可以看到,成功过滤

		FilteredAdapter.Filter filter = new FilteredAdapter.Filter();
        //  此处过滤掉不是 p 数据的
        filter.p = new String[]{"p","",""};
        log.info("{}",enforcer.getAllSubjects());
        enforcer.loadFilteredPolicy(filter);
        log.info("{}",enforcer.getAllSubjects());

在这里插入图片描述

三、扩充功能部分

请自行参看文档扩充功能部分

四、API部分

  • 含有name的,一般可用于指定ptype(也就是p,g)
  • 含有Ex的的,一般可用于解释执行内容
  • 含有Batch的,一般可接收数组参数,批量执行

五、其他

多数据源

@Configuration
public class CasbinDataSourceConfiguration {
    @Bean
    @CasbinDataSource
    public DataSource casbinDataSource() {
        return DataSourceBuilder.create().url("jdbc:h2:mem:casbin").build();
    }
}

异常设定

在这里插入图片描述

附录

[1]官方文档
[2]官方实例-一般版本
[3]官方实例-SpringBoot版本

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react事件系统(老版本)

带着问题阅读探索 React 为什么有自己的事件系统&#xff1f;什么是事件合成 &#xff1f;如何实现的批量更新&#xff1f;事件系统如何模拟冒泡和捕获阶段&#xff1f;如何通过 dom 元素找到与之匹配的fiber&#xff1f;为什么不能用 return false 来阻止事件的默认行为&…

python【PyQt5】的环境搭建和使用(全网最全)其一

什么是pyQT pyqt是一个用于创建GUI应用程序的跨平台工具包&#xff0c;它将python与qt库融为一体。也就是说&#xff0c;pyqt允许使用python语言调用qt库中的API。这样做的最大好处就是在保存了qt高运行效率的同时&#xff0c;大大提高开发效率。因为&#xff0c;使用python语言…

城市路边停车收费系统/停车收费管理系统

摘 要 近年来&#xff0c;随着社会的进步和发展&#xff0c;车辆也在迅速增加&#xff0c;城市交通的瓶颈不仅体现在道路交通的拥挤上&#xff0c;也体现在传统停车场管理效率和安全性大大滞后于社会的需要&#xff0c;给人们的生活带来了极大的不便。尤其&#xff0c;随着汽车…

二、MongoDB简介及基本操作

mongodb是一个基于文档的强大、灵活、易于扩展的通用型数据库。是基于分布式文件存储的数据库。其由 C 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。 mongodb也是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&…

运动健身买什么耳机好用、最优秀的健身耳机推荐分享

冬天绝对是个减肥的好季节&#xff0c;因为这个季节天气比较冷&#xff0c;我们在运动过程中消耗的热量也就会更多&#xff0c;因此选择一款不错的运动耳机来用坚持就显得尤为重要了。这款运动耳机要能稳定在耳朵上&#xff0c;还要具备防水功能&#xff0c;同时音质上也要有保…

闲人闲谈PS之三十四——项目成本费用控制阈值

**惯例闲话&#xff1a;**最近有小伙伴问闲人有没有PS顾问资源&#xff0c;闲人问了一圈&#xff0c;结果发现都没有档期&#xff0c;不免让闲人有些失落&#xff0c;好心答应帮忙&#xff0c;结果帮不上…但是隐隐约约觉得在几年前说的话被应验了&#xff0c;PS模块一定是个热…

Ubuntu G++ 编译C++源文件

工程项目代码简短的时候使用 G 进行功能模块测试 过程分为&#xff1a; 预处理&#xff1a;展开头文件&#xff0c;去掉主食&#xff0c;条件编译和文件包含编译&#xff1a;检查语法&#xff0c;生成汇编代码汇编&#xff1a;汇编代码转换成机器码链接&#xff1a;Link 主要是…

王学岗音视频开发(一)—————配置NDK开发环境

Android studio准备 Android studio需要下载Android6.0版本(Android SDK Platform 23)&#xff0c;最小支持Android6.0 NDK 下载 cmake下载安装 Android studio 代理配置 dl.google.com可能会被屏蔽&#xff0c;首先查下其IP地址。查到IP地址后修改etc/hosts文件。 Andr…

pytorch深度学习实战lesson25

第二十五课 network in network(NIN) NIN 叫做network in network或者叫做网络中的网络。这个网络现在用的不多&#xff0c;几乎很少被用到。但是它里面提出了比较重要的概念&#xff0c;在之后很多网络都会被持续的用到。所以今天认识一下这一个网络。 目录 理论部分 实践部…

高并发下丢失更新的解决方案

作者&#xff1a;谢益培 1 背景 关键词&#xff1a;并发、丢失更新 预收款账户表上有个累计抵扣金额的字段&#xff0c;该字段的含义是统计商家预收款账户上累计用于抵扣结算成功的金额数。更新时机是&#xff0c;账单结算完成时&#xff0c;更新累计抵扣金额累计抵扣金额账…

ImmunoChemistry艾美捷Annexin V-FITC细胞凋亡检测试剂盒方案

膜联蛋白V是具有血管抗凝血活性的钙和磷脂结合蛋白家族的成员。体外实验结果表明&#xff0c;它可能通过与凝血酶原竞争磷脂酰丝氨酸&#xff08;PS&#xff09;结合位点而在抑制凝血中发挥作用。在健康细胞中&#xff0c;PS通常保存在细胞膜的内小叶&#xff08;胞质侧&#x…

网络是怎样连接的--TCP大致控制流程

文章目录5.1 协议栈内部结构5.2 套接字作用5.3 创建套接字5.4 两类控制信息5.5 连接操作的实际过程5.6 收发数据5.6.1将http请求消息发给协议栈5.6.2 注意对较大数据进行拆分5.6.3 序号和ACK5.6.4 等待超时时间5.6.5 窗口机制提升效率5.6.6 ACK与窗口合并5.7 断开连接5.8 删除套…

MCE | 新冠 德尔塔病毒

冠状病毒&#xff0c;其表面有突出的棒状尖峰&#xff0c;在电镜下可以观察到像王冠一样的放射状凸起而得名。冠状病毒的基本结构如图 1 所示&#xff0c;包括刺突糖蛋白 (S)、包膜 (E)、膜 (M) 和核衣壳 (N)。 图 1. 冠状病毒结构2020 年石正丽教授在 Nature 发表的论文 A …

浅识JVM

⭐️前言⭐️ 本篇文章&#xff0c;博主分享的是在面试中JVM常考的考点&#xff0c;希望这篇文章能够对你有用。 &#x1f349;博客主页&#xff1a; &#x1f341;【如风暖阳】&#x1f341; &#x1f349;精品Java专栏【JavaSE】、【备战蓝桥】、【JavaEE初阶】、【MySQL】、…

多维度比对三种软件开发方式后,无代码开发到底赢在哪?

近年来受信息化、数字化和 5G、云计算发展的影响&#xff0c;以及企业管理的不确定性和复杂性增加&#xff0c;国内管理软件的需求及行业市场整体规模也连年高速增长&#xff0c;进而带动了管理软件开发方式的变革。 但是由于传统自主及外包开发方式存在的周期长、成本高、不能…

DataX二次开发——(9)新增s3reader和s3writer模块

1 背景 DataX3.0支持阿里的OSS的读写&#xff0c;但没支持S3的读写&#xff0c;虽然OSS的也是基于S3协议去做二开的&#xff0c;但是一些参数有点区别&#xff0c;所以按照阿里的OSSReader和OSSWriter开发了S3Reader和S3Writer。 2 代码开发 2.1 s3reader 2.1.1 项目结构 2…

pytorch快速上手(8)-----pytorch优化器简介

文章目录一、简介二、optimizer属性方法1. zero_grad()2. step()3. add_param_group()4. state_dict()5. load_state_dict()学习率动量三、常见优化器介绍1. BGD&#xff08;Batch Gradient Descent&#xff09;2. Stochastic Gradient Descent&#xff08;SGD&#xff09;3. M…

记录一次因执行时间过长锁已经释放导致finally块再次unlock引发的异常

一、前言 因为我的一个需求需要请求一个耗时比较长的接口&#xff08;耗时长其实是对接方的锅&#xff09;&#xff0c;该接口交给了Spring事务管理&#xff0c;并且使用了分布式锁&#xff0c;但是在请求的时候&#xff0c;出现error,看日志发现是unlock的时候没有锁可以去解…

牛客网语法篇练习复合类型(二)

1.输入NxM矩阵&#xff0c;矩阵元素均为整数&#xff0c;计算其中大于零的元素之和。 a,b map(int,input().split()) list1 [] sum 0 for i in range(a):list1.extend(list(map(int,input().split()))) for i in list1:if i>0:sumi print(sum) 2.给你一个整数n&#xff…

辨别代码能否引发线程安全问题--避免在平时写代码时引发线程安全问题

前景提要&#xff1a; 本篇文章只是入门&#xff0c;目的在于在脑海中构建一个Java运行的模型&#xff0c;然后可以在平时写代码时对是否引发线程安全问题有感知。 文章目录引入了解辨别线程安全问题之前先来构建一个计算机运行模型了解线程安全问题怎么能不知道线程和进程了解…