作者: iuu

navicat for Windows 16/17无限试用脚本

echo Delete HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPremium\Update
reg delete HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPremium\Update /f
echo Delete HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPremium\Registration[version and language]
for /f %%i in ('"REG QUERY "HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPremium" /s | findstr /L Registration"') do (
    reg delete %%i /va /f
)

echo Delete Info and ShellFolder under HKEY_CURRENT_USER\Software\Classes\CLSID
for /f "tokens=*" %%a in ('reg query "HKEY_CURRENT_USER\Software\Classes\CLSID"') do (
  for /f "tokens=*" %%l in ('reg query "%%a" /f "Info" /s /e ^| findstr /i "Info"') do (
    echo Delete: %%a
    reg delete %%a /f
  )
  for /f "tokens=*" %%l in ('reg query "%%a" /f "ShellFolder" /s /e ^| findstr /i "ShellFolder"') do (
    echo Delete: %%a
    reg delete %%a /f
  )
)

来源 https://linux.do/t/topic/100400/67

复盘Casbin权限框架

Casbin的工作原理

在 Casbin 中, 访问控制模型被抽象为基于 PERM (Policy, Effect, Request, Matcher) [策略,效果,请求,匹配器]的一个文件。

Policy:定义权限的规则
Effect:定义组合了多个Policy之后的结果
Request:访问请求
Matcher:判断Request是否满足Policy

首先会定义一堆Policy,让后通过Matcher来判断Request和Policy是否匹配,然后通过Effect来判断匹配结果是Allow还是Deny。

Policy
Policy 主要表示访问控制关于角色、资源、行为的具体映射关系。

Casbin的核心概念

Model

Model是Casbin的具体访问模型,其主要以文件的形式出现,该文件常常以.conf最为后缀。

Model CONF 至少应包含四个部分:
[request_definition],
[policy_definition],
[policy_effect],
[matchers]。
如果 model 使用 RBAC, 还需要添加[role_definition]部分。
Model CONF 文件可以包含注释。注释以 # 开头, # 会注释该行剩余部分。

比如:

# 请求定义 
# 用于request的定义,它明确了e.Enforce(...)函数中参数的定义,sub, obj, act 表示经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action)。
[request_definition]
r = sub, obj, act

# 策略定义
# 用于policy的定义,每条规则通常以形如p的policy type开头,比如p,joker,data1,read就是一条joker具有data1读权限的规则。
[policy_definition]
p = sub, obj, act

# 角色定义
# 是RBAC角色继承关系的定义。g 是一个 RBAC系统,_, _表示角色继承关系的前项和后项,即前项继承后项角色的权限。
[role_definition]
g = _, _

# policy_effect:是对policy生效范围的定义,它对request的决策结果进行统一的决策,比如e = some(where (p.eft == allow))就表示如果存在任意一个决策结果为allow的匹配规则,则最终决策结果为allow。p.eft 表示策略规则的决策结果,可以为allow 或者deny,当不指定规则的决策结果时,取默认值allow 。
[policy_effect]
e = some(where (p.eft == allow))

# 匹配器定义
# 定义了策略匹配者。匹配者是一组表达式,它定义了如何根据请求来匹配策略规则
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

在Casbin中,访问控制模型被抽象为基于PERM元模型(策略 = Policy ,效果 = Effect,请求 = Request,匹配器 = Matcher)的CONF文件。

为项目切换或升级授权机制就像修改配置一样简单。 您可以通过组合可用模型来定制自己的访问控制模型。

例如,您可以在一个模型内部将RBAC角色和ABAC属性结合在一起,并共享一套策略规则。

策略 一般存储到数据库 因为会有很多!!!!

定义Policy

定义Matcher

Request 与 Policy 进行匹配,获得一个Effect

拿到 Effect 的结果到 Effect 的表达式 返回一个布尔值

Request == 请求

定义请求参数。 基本请求是一个元组对象,至少需要一个主体(被访问实体),对象(被访问资源)和动作(访问方法)。

例如,请求定义可能看起来像这样:

r={sub,obj,act}
# r={被访问主体,被访问资源,动作或方法}

此定义指定了访问控制匹配函数所需的参数名称和顺序。

Policy == 策略

定义访问策略的模型。 它指定了策略规则文档中字段的名称和顺序。

例如:

p={sub, obj, act} 或 p={sub, obj, act, eft}

注意:如果未定义eft(策略结果),则不会读取策略文件中的结果字段,匹配策略结果将默认允许。

Matcher == 匹配

定义请求和策略的匹配规则。

例如:

m = r.sub == p.sub && r.act == p.act && r.obj == p.obj 

这个简单而常见的匹配规则意味着,如果请求的参数(被访问主体,被访问资源,动作或方法)等于策略中找到的那些,那么返回策略结果(p.eft)。 策略的结果将保存在p.eft中。

Effect == 效果

对匹配器的匹配结果进行逻辑组合判断。

例如:

e = some(where(p.eft == allow))

这个语句意味着,如果匹配策略结果p.eft有(一些)允许的结果,那么最终结果为真。

让我们看另一个例子:

e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

这个例子组合的逻辑意义是:如果有一个策略匹配到允许的结果,并且没有策略匹配到拒绝的结果,结果为真。 换句话说,当匹配策略都是允许时,结果为真。 如果有任何拒绝,两者都为假(更简单地说,当允许和拒绝同时存在时,拒绝优先)。

ACL

Casbin中最基本和最简单的模型是ACL。
ACL的模型CONF如下:

# 请求
[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

ACL模型的一个示例策略为:

p, 张三, data1, read
p, 李四, data2, write

这意味着:

张三 可以读取data1
李四 可以写入data2
我们还支持通过在末尾添加 '\' 来进行多行模式:

# 匹配
[matchers]
m = r.sub == p.sub && r.obj == p.obj \
&& r.act == p.act

此外,如果您正在使用ABAC,您可以尝试如下例子中的'in'操作符,该例子是Casbin golang版本的(jCasbin和Node-Casbin还不支持):

# 匹配
[matchers]
m = r.obj == p.obj && r.act == p.act || r.obj in ('data2', 'data3')

但是你必须确保数组的长度超过 1,否则会引发难以恢复的错误(panic)。

参考教程

国高办公系统
https://www.bilibili.com/video/BV1qz4y167XP/
https://blog.csdn.net/weixin_51991615/article/details/123746169
https://darjun.github.io/2020/06/12/godailylib/casbin/
https://casbin.org/zh/docs/how-it-works
https://casbin.org/zh/editor
https://github.com/casbin/gorm-adapter
https://casbin.org/zh/docs/adapters/#%E6%94%AF%E6%8C%81%E7%9A%84%E9%80%82%E9%85%8D%E5%99%A8
https://juejin.cn/post/7133456877605617678
https://medium.com/@mehul25/casbin-rbac-with-domains-92680bd28d2e
https://medium.com/@mehul25/casbin-groups-and-roles-6c279aa918b

复盘orm库gorm框架

gorm是一个使用Go语言编写的ORM框架。它文档齐全,对开发者友好,支持主流数据库。
基础配置

type DbConfig struct {
    DbHost        string `mapstructure:"db_host" json:"db_host" yaml:"db_host"`
    DbPort        int    `mapstructure:"db_port" json:"db_port" yaml:"db_port"`
    DbName        string `mapstructure:"db_name" json:"db_name" yaml:"db_name"`
    DbUser        string `mapstructure:"db_user" json:"db_user" yaml:"db_user"`
    DbPass        string `mapstructure:"db_pass" json:"db_pass" yaml:"db_pass"`
    TablePrefix   string `mapstructure:"table_prefix" json:"table_prefix" yaml:"table_prefix"`
    TimeZone      string `mapstructure:"time_zone" json:"time_zone" yaml:"time_zone"`
    LogLevel      int    `mapstructure:"log_level" json:"log_level" yaml:"log_level"`                // LogLevel SQL日志级别 (1-静音 2-错误 3-警告 4-信息)
    SlowThreshold int    `mapstructure:"slow_threshold" json:"slow_threshold" yaml:"slow_threshold"` // SlowThreshold 慢SQL阈值(毫秒)。慢SQL会在log_level大于等于3时输出。
    IdleConns     int    `mapstructure:"idle_conns" json:"idle_conns" yaml:"idle_conns"`             // 空闲连接池中的最大连接数,建议为open_conns的百分之5-20之间
    OpenConns     int    `mapstructure:"open_conns" json:"open_conns" yaml:"open_conns"`             // 最大打开连接数,建议这里设置为50
}

func InitGorm(conf *config.Config) *gorm.DB {
    dsn := fmt.Sprintf("host=%s port=%d dbname=%s user=%s password=%s sslmode=disable TimeZone=%s",
        conf.Db.DbHost, conf.Db.DbPort, conf.Db.DbName, conf.Db.DbUser, conf.Db.DbPass, conf.Db.TimeZone)
    postgresConfig := postgres.Config{
        DSN:                  dsn,  // DSN data source name
        PreferSimpleProtocol: true, // 禁用隐式 prepared statement
    }

    // 使用标准日志库的New方法创建日志输出
    //newLogger := logger.New(
    //  log.New(os.Stdout, "\r\n", log.LstdFlags),
    //  logger.Config{
    //      SlowThreshold:             time.Duration(dbConf.SlowThreshold) * time.Millisecond, // 慢SQL阈值
    //      LogLevel:                  logger.LogLevel(dbConf.LogLevel),                       // 日志级别
    //      IgnoreRecordNotFoundError: true,
    //      Colorful:                  true,
    //  })

    // zap 自定义
    newLogger := NewGormLogger(x_logger.GormZapLog.GetZapLogger(), logger.LogLevel(conf.Db.LogLevel))

    PGDB, err := gorm.Open(postgres.New(postgresConfig), &gorm.Config{
        //Logger: newLogger,
        //Logger: logger.Default.LogMode(logger.Info),
        Logger: newLogger,
        NamingStrategy: schema.NamingStrategy{
            SingularTable: false, // 使用单数表名,在启用此选项的情况下,“user”的表将是“user”
            TablePrefix:   "te_", // 表前缀
        },
    })

    DB := PGDB

    if err != nil {
        fmt.Println("数据库链接失败")
        os.Exit(0)
    }
    AutoMigrate(DB)
    sqlDB, _ := DB.DB()
    sqlDB.SetMaxIdleConns(conf.Db.IdleConns)
    sqlDB.SetMaxOpenConns(conf.Db.OpenConns)
    // 设置数据库连接池中连接的最大生命周期
    sqlDB.SetConnMaxLifetime(time.Hour)
    fmt.Println("[+]PG连接成功!")
    return DB
}

// AutoMigrate 自动迁移
func AutoMigrate(db *gorm.DB) {
    err := db.AutoMigrate(
        new(model.User),
    )
    if err != nil {
        fmt.Println("[-] 迁移数据表失败:", err.Error())
        os.Exit(0)
    }
}

基础的数据操作

    // 获取表名
    m := &model.User{}
    modelType := reflect.TypeOf(m).Elem()
    fmt.Println(modelType)
    tableName := global.Db.NamingStrategy.TableName("User")
    fmt.Println(tableName)
    //
    // 插入一条记录
    user := model.User{Name: "刘建超"}
    result := global.Db.Create(&user) // 在数据库中插入一条新记录
    fmt.Println(result.Error)         // 如果有错误,打印错误
    fmt.Println(user.ID)              // 打印插入后生成的 ID
    fmt.Printf("%#v", user)           // 打印插入后生成的 ID

    // Save 修改记录
    user = model.User{Name: "刘建超iuu"}
    user.ID = 1
    // 排除指定字段
    global.Db.Omit("Created").Save(&user)

    // 软删除
    global.Db.Delete(&user)

    // 如果主键为空,插入新记录
    user = model.User{Name: "iuu"}
    global.Db.Save(&user)

    user = model.User{Name: "刘建超iuuxxx"}
    user.ID = 2
    global.Db.Select("Name").Save(&user)

    //永久删除
    global.Db.Unscoped().Delete(&user)

Docker安装PostgreSQL

Docker安装PostgreSQL

拉取镜像

docker pull postgres:latest

用于生成默认的配置文件

docker run -i --rm postgres cat /usr/share/postgresql/postgresql.conf.sample > my-postgres.conf

启动容器

docker run -d \
-p 15432:5432 \
--restart=always \
--name docker-postgres \
--privileged=true \
-e TZ=Asia/Shanghai \
-e PGTZ=Asia/Shanghai \
-e POSTGRES_USER=iuu_postgres \
-e POSTGRES_PASSWORD=iuu_postgres \
-v /home/Software/Docker/postgres/postgres.conf:/etc/postgresql/postgresql.conf \
-v /home/Software/Docker/postgres/data:/var/lib/postgresql/data \
postgres:latest \
-c 'config_file=/etc/postgresql/postgresql.conf'

进入容器

docker exec -it docker-postgres  /bin/bash
# 直接进入pgsql
docker exec -it docker-postgres psql -U iuu_postgres

查看所有数据库

\list

查看所有数据库

SELECT datname FROM pg_database;

查看当前时区

show time zone; 或者 show timezone;

查看数据库的时区与时间:

SELECT now();

查看数据库可供选择的时区:

select * from pg_timezone_names;

设置时区:

set time zone "Asia/Shanghai";

但是通过这种方式设置时区在你退出psql终端后,再次进入此psql中断后就会发现又恢复到原来的时区了,如果想永久修改,我们需要更改配置文件:

log_timezone = 'PRC'
timezone = 'PRC'
# 'PRC' 改为 'Asia/Shanghai'

复盘配置库viper框架

Viper是适用于Go应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。
main函数基本配置如下

package main

import "vipertest/core"

func main() {
    //core.InitYamlViper("./yaml.yaml")
    //core.InitTomlViper("./toml.toml")
    //core.InitJsonViper("./json.json")
    core.InitIniViper("./ini.ini")

    select {}
}

程序根目录创建几个格式的配置文件
ini格式

[database]
server=127.0.0.1
ports=8003,8004,8007

[servers.alpha]
ip=127.0.0.1

json格式

{
  "database": {
    "server": "127.0.0.1",
    "ports": [8003, 8004, 8007]
  },
  "servers": {
    "alpha": {
      "ip": "127.0.0.1"
    }
  }
}

yaml格式

database:
  server: 127.0.0.1
  ports:
    - 8003
    - 8004
    - 8007

servers:
  alpha:
    ip: 127.0.0.1

toml格式

[database]
server = "127.0.0.1"
ports = [ 8004, 8005, 8006 ]

[servers]
[servers.alpha]
ip = "127.0.0.1"

核心代码如下

package core

import (
    "fmt"
    "github.com/fsnotify/fsnotify"
    "github.com/spf13/viper"
)

type DatabaseConfig struct {
    Server string `mapstructure:"server" json:"server" yaml:"server"`
    Ports  []int  `mapstructure:"ports" json:"ports" yaml:"ports"`
}

type ServersConfig struct {
    Alpha ServerInfo `mapstructure:"alpha" json:"alpha" yaml:"alpha"`
}

type ServerInfo struct {
    IP string `mapstructure:"ip" json:"ip" yaml:"ip"`
}

type Ini struct {
    Database DatabaseConfig `json:"database" ini:"database"`
    Servers  ServersConfig  `json:"servers" ini:"servers"`
}

var IniConf Ini

type Json struct {
    Database DatabaseConfig `json:"database"`
    Servers  ServersConfig  `json:"servers"`
}

var JsonConf Json

type Toml struct {
    Database DatabaseConfig `toml:"database"`
    Servers  ServersConfig  `toml:"servers"`
}

var TomlConf Toml

type Yaml struct {
    Database DatabaseConfig `yaml:"database"`
    Servers  ServersConfig  `yaml:"servers"`
}

var YamlConf Yaml

// InitYamlViper 解析yaml格式文件
func InitYamlViper(path string) {
    v := viper.New()
    // 指定配置文件路径
    v.SetConfigFile(path)
    // 如果配置文件的名称中没有扩展名,则需要配置此项
    v.SetConfigType("yaml")
    // 查找并读取配置文件
    err := v.ReadInConfig()
    if err != nil {
        fmt.Printf("读取配置文件错误: %s \n", err)
    }
    // 监控并重新读取配置文件
    v.WatchConfig()
    v.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("配置文件内容已更改:", e.Name)
        fmt.Println("all settings: ", v.AllSettings())
        fmt.Println("database.server: ", v.GetString("database.server"))
        fmt.Println("database.ports: ", v.GetIntSlice("database.ports"))
        fmt.Println("--------------")
        fmt.Println("servers.alpha.ip: ", v.GetString("servers.alpha.ip"))

        if err = v.Unmarshal(&YamlConf); err != nil {
            fmt.Printf("重新解析配置文件失败: %s \n", err)
        }

        fmt.Printf("新配置为:%#v\n", YamlConf)
        fmt.Printf("新配置database.ports: %#v\n", YamlConf.Database.Ports)

    })

    fmt.Println("all settings: ", v.AllSettings())
    fmt.Println("database.server: ", v.GetString("database.server"))
    fmt.Println("database.ports: ", v.GetIntSlice("database.ports"))
    fmt.Println("--------------")
    fmt.Println("servers.alpha.ip: ", v.GetString("servers.alpha.ip"))
    if err = v.Unmarshal(&YamlConf); err != nil {
        fmt.Printf("解析配置文件失败: %s \n", err)
    }
    fmt.Printf("配置为:%#v\n", YamlConf)
    fmt.Printf("database.ports: %#v\n", YamlConf.Database.Ports)

}

// InitTomlViper 解析toml格式文件
func InitTomlViper(path string) {
    v := viper.New()
    // 指定配置文件路径
    v.SetConfigFile(path)
    // 如果配置文件的名称中没有扩展名,则需要配置此项
    v.SetConfigType("toml")
    // 查找并读取配置文件
    err := v.ReadInConfig()
    if err != nil {
        fmt.Printf("读取配置文件错误: %s \n", err)
    }
    // 监控并重新读取配置文件
    v.WatchConfig()
    v.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("配置文件内容已更改:", e.Name)
        fmt.Println("all settings: ", v.AllSettings())
        fmt.Println("database.server: ", v.GetString("database.server"))
        fmt.Println("database.ports: ", v.GetIntSlice("database.ports"))
        fmt.Println("--------------")
        fmt.Println("servers.alpha.ip: ", v.GetString("servers.alpha.ip"))

        if err = v.Unmarshal(&TomlConf); err != nil {
            fmt.Printf("重新解析配置文件失败: %s \n", err)
        }
        fmt.Printf("新配置为:%#v\n", TomlConf)
        fmt.Printf("新配置database.ports: %#v\n", TomlConf.Database.Ports)

    })
    fmt.Println("all settings: ", v.AllSettings())
    fmt.Println("database.server: ", v.GetString("database.server"))
    fmt.Println("database.ports: ", v.GetIntSlice("database.ports"))
    fmt.Println("--------------")
    fmt.Println("servers.alpha.ip: ", v.GetString("servers.alpha.ip"))
    if err = v.Unmarshal(&TomlConf); err != nil {
        fmt.Printf("解析配置文件失败: %s \n", err)
    }
    fmt.Printf("配置为:%#v\n", TomlConf)
    fmt.Printf("database.ports: %#v\n", TomlConf.Database.Ports)
}

// InitJsonViper 解析json格式文件
func InitJsonViper(path string) {
    v := viper.New()
    // 指定配置文件路径
    v.SetConfigFile(path)
    // 如果配置文件的名称中没有扩展名,则需要配置此项
    v.SetConfigType("json")
    // 查找并读取配置文件
    err := v.ReadInConfig()
    if err != nil {
        fmt.Printf("读取配置文件错误: %s \n", err)
    }
    // 监控并重新读取配置文件
    v.WatchConfig()
    v.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("配置文件内容已更改:", e.Name)
        fmt.Println("all settings: ", v.AllSettings())
        fmt.Println("database.server: ", v.GetString("database.server"))
        fmt.Println("database.ports: ", v.GetIntSlice("database.ports"))
        fmt.Println("--------------")
        fmt.Println("servers.alpha.ip: ", v.GetString("servers.alpha.ip"))

        if err = v.Unmarshal(&JsonConf); err != nil {
            fmt.Printf("重新解析配置文件失败: %s \n", err)
        }
        fmt.Printf("新配置为:%#v\n", JsonConf)
        fmt.Printf("新配置database.ports: %#v\n", JsonConf.Database.Ports)

    })
    fmt.Println("all settings: ", v.AllSettings())
    fmt.Println("database.server: ", v.GetString("database.server"))
    fmt.Println("database.ports: ", v.GetIntSlice("database.ports"))
    fmt.Println("--------------")
    fmt.Println("servers.alpha.ip: ", v.GetString("servers.alpha.ip"))
    if err = v.Unmarshal(&JsonConf); err != nil {
        fmt.Printf("解析配置文件失败: %s \n", err)
    }
    fmt.Printf("配置为:%#v\n", JsonConf)
    fmt.Printf("database.ports: %#v\n", JsonConf.Database.Ports)
}

// InitIniViper 解析ini格式文件
func InitIniViper(path string) {
    v := viper.New()
    // 指定配置文件路径
    v.SetConfigFile(path)
    // 如果配置文件的名称中没有扩展名,则需要配置此项
    v.SetConfigType("ini")
    // 查找并读取配置文件
    err := v.ReadInConfig()
    if err != nil {
        fmt.Printf("读取配置文件错误: %s \n", err)
    }
    // 监控并重新读取配置文件
    v.WatchConfig()
    v.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("配置文件内容已更改:", e.Name)
        fmt.Println("all settings: ", v.AllSettings())
        fmt.Println("database.server: ", v.GetString("database.server"))
        fmt.Println("database.ports: ", v.GetStringSlice("database.ports"))
        fmt.Println("--------------")
        fmt.Println("servers.alpha.ip: ", v.GetString("servers.alpha.ip"))

        if err = v.Unmarshal(&IniConf); err != nil {
            fmt.Printf("重新解析配置文件失败: %s \n", err)
        }
        fmt.Printf("新配置为:%#v\n", IniConf)
        fmt.Printf("新配置database.ports: %#v\n", IniConf.Database.Ports)

    })
    fmt.Println("all settings: ", v.AllSettings())
    fmt.Println("database.server: ", v.GetString("database.server"))
    fmt.Println("database.ports: ", v.GetStringSlice("database.ports"))
    fmt.Println("--------------")
    fmt.Println("servers.alpha.ip: ", v.GetString("servers.alpha.ip"))
    if err = v.Unmarshal(&IniConf); err != nil {
        fmt.Printf("解析配置文件失败: %s \n", err)
    }
    fmt.Printf("配置为:%#v\n", IniConf)
    fmt.Printf("database.ports: %#v\n", IniConf.Database.Ports)
}
1 3 4 5 6 7 16