标题:【Redis12】Redis基础:ACL与GEO命令

文章目录
    分类:存储运维 标签:Redis

    Redis基础学习:ACL与GEO命令

    标题说的可能不太清楚,ACL 是权限控制,GEO 是地理位置信息。是不是感觉高大上又很好玩?ACL 是新东西,Redis6 之后才出来的,而 GEO 相关的功能就比较早了,Redis3.2 版本的时候就已经有了。那么我们就一个一个的来看看吧。

    ACL

    ACL 的全称是 Access Control List ,也就是 访问控制列表 的意思,在权限这块还有 RBAC、ABAC 等,大家在做后台的时候可能都接触过。另外在很多系统中都会有 ACL 这个概念,比如 Linux 。


    默认的情况下,我们通过 redis.conf 设置中的 requirepass 设置密码,然后在客户端使用 AUTH 登录。这种验证形式的问题想必大家也能猜到,主要就是控制粒度太粗,只有一个密码控制能不能访问能不能用,无法实现精细控制。比如说不同的用户可以有不同的密码,不同的权限,有的只能读,有的只能写。这些问题,ACL 都可以解决。


    我们先来看看它的相关命令帮助信息,ACL 也是一个包含多个子命令的复合命令。

    127.0.0.1:6379> ACL HELP
     1) ACL <subcommand> [<arg> [value] [opt] ...]. Subcommands are:
     2) CAT [<category>]
     3)     List all commands that belong to <category>, or all command categories
     4)     when no category is specified.
     5) DELUSER <username> [<username> ...]
     6)     Delete a list of users.
     7) GETUSER <username>
     8)     Get the user's details.
     9) GENPASS [<bits>]
    10)     Generate a secure 256-bit user password. The optional `bits` argument can
    11)     be used to specify a different size.
    12) LIST
    13)     Show users details in config file format.
    14) LOAD
    15)     Reload users from the ACL file.
    16) LOG [<count> | RESET]
    17)     Show the ACL log entries.
    18) SAVE
    19)     Save the current config to the ACL file.
    20) SETUSER <username> <attribute> [<attribute> ...]
    21)     Create or modify a user with the specified attributes.
    22) USERS
    23)     List all the registered usernames.
    24) WHOAMI
    25)     Return the current connection username.
    26) HELP
    27)     Prints this help.

    在默认情况下,我们登录的用户会在 ACL 中生成一个 default 用户,可以通过 ACL LIST 查看。

    127.0.0.1:6379> ACL LIST
    1) "user default on nopass ~* &* +@all"

    如果想增加一个用户,可以使用 ACL SETUSER 命令。

    127.0.0.1:6379> ACL SETUSER zy
    OK
    127.0.0.1:6379> ACL LIST
    1) "user default on nopass ~* &* +@all"
    2) "user zy off &* -@all"

    好了,添加和查看有了,在讲后面的内容之前,我们先来看看查看到的用户信息里面的这些内容都是啥意思。


    一条用户数据的格式其实是:

    user 用户名 是否启用on|off 密码 ~key名规则 &Pub|Sub通道规则 +|-命令规则

    还是有点晕吧?没事,我们拆开来看。


    user 是都有的,这个不多说,紧跟着 user 后面的就是用户名,然后就是用户是否启用的开关,比如 default 是 on ,而 zy 是 off ,再下一个是密码,default 显示的是 nopass 表示不用密码,而 zy 我们还没有设置密码。


    要切换用户的话需要先设置密码,因为 AUTH 命令在默认情况下是需要密码的。

    127.0.0.1:6379> auth zy
    (error) ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?
    127.0.0.1:6379> auth zy 123456
    (error) WRONGPASS invalid username-password pair or user is disabled.

    上面两段测试登录 zy 用户,第一段 AUTH 没有加密码,直接返回需要密码才能切换。第二个我随便写了个密码,返回的是用户未启用。


    好吧,那么我们就启用一下用户,然后再加一些别的属性。

    127.0.0.1:6379> ACL SETUSER zy on >123456 ~cached:* +get
    OK
    127.0.0.1:6379> auth zy 123456
    OK

    现在登录没问题了,我们已经切换到了 zy 这个用户下面,不过同时我们加了一个 ~cached:* 和 +get 这两个属性。它们又是干嘛的呢?

    • ~ 表示的是我们可以操作的 key 名规则,在这里设置成了 ~cached:* ,表示这个用户只能操作 cached: 开头的 key

    • + 和 - 表示的是增加或者去掉某些命令的权限,目前我们只有一个 get 命令的权限

    看着晕吗?不怕,测试下。

    127.0.0.1:6379> get a
    (error) NOPERM this user has no permissions to access one of the keys used as arguments
    127.0.0.1:6379> get cached:a
    (nil)
    127.0.0.1:6379> set cached:a 111
    (error) NOPERM this user has no permissions to run the 'set' command or its subcommand

    首先尝试获取 a ,直接报出没权限的错误,然后使用 GET 命令查询 cached:a ,可以正常返回,不过是一个 nil ,因为我们没有设置 cached:a ,那么我们尝试使用 SET 设置一下,又返回了没有使用 SET 命令权限的错误。


    是不是感觉很强大了?确实,这一套 ACL 的能力真的非常强大,该有的权限控制能力基本全有了。我们可以通过 ACL GETUSER 来查看当前用户的权限信息。

    127.0.0.1:6379> ACL GETUSER zy
     1) "flags"
     2) 1) "on"
        2) "allchannels"
     3) "passwords"
     4) 1) "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
     5) "commands"
     6) "-@all +get"
     7) "keys"
     8) 1) "cached:*"
     9) "channels"
    10) 1) "*"
    
    127.0.0.1:6379> ACL GETUSER zy
    1# "flags" => 1~ "on"
       2~ "allchannels"
    2# "passwords" => 1) "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
    3# "commands" => "-@all +get"
    4# "keys" => 1) "cached:*"
    5# "channels" => 1) "*"

    下面是切换成 RSEP3 格式查看的,更清晰一些,忘了啥是 RSEP3 ?赶紧回去学习 Redis基础学习:客户端操作https://mp.weixin.qq.com/s/TEjwPuP3tPYwOprkg7FcPQ


    好了,继续测试,添加上 SET 命令的权限吧,注意,要新开个客户端,用 default 或者其它有 ACL 命令权~~~~限的用户来添加哦。

    // default用户
    127.0.0.1:6379> ACL SETUSER zy +set
    OK
    127.0.0.1:6379> ACL GETUSER zy
    1# "flags" => 1~ "on"
       2~ "allchannels"
    2# "passwords" => 1) "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
    3# "commands" => "-@all +set +get"
    4# "keys" => 1) "cached:*"
    5# "channels" => 1) "*"
    
    // zy用户
    127.0.0.1:6379> set cached:a 111
    OK
    127.0.0.1:6379> get cached:a
    "111"

    现在可以正常 GET 和 SET 了吧,不过这样一个一个配置吗?Redis 200 多个命令呢,没事,还有更方便的方法,看到 default 的 +@all 了嘛。

    127.0.0.1:6379> ACL SETUSER zy +@all ~*
    OK
    127.0.0.1:6379> auth zy 123456
    OK
    127.0.0.1:6379> ACL WHOAMI
    "zy"
    127.0.0.1:6379> lpush b 1
    OK
    127.0.0.1:6379> lpop b 1
    1

    这下啥都有了吧,命令全都有了,而且把 ~ 也设置成 * 了,也就是所有 key 名称都可以操作了。不过这样配置的话,要么太细,要么太粗,有没有折中一点的?最好是有权限组这样的功能就好了。这个嘛,Redis 的开发者们早就想到了。

    127.0.0.1:6379> ACL CAT
     1) "keyspace"
     2) "read"
     3) "write"
     4) "set"
     5) "sortedset"
     6) "list"
     7) "hash"
     8) "string"
     9) "bitmap"
    10) "hyperloglog"
    11) "geo"
    12) "stream"
    13) "pubsub"
    14) "admin"
    15) "fast"
    16) "slow"
    17) "blocking"
    18) "dangerous"
    19) "connection"
    20) "transaction"
    21) "scripting"
    
    127.0.0.1:6379> ACL CAT geo
     1) "georadiusbymember_ro"
     2) "geosearchstore"
     3) "georadiusbymember"
     4) "geohash"
     5) "geopos"
     6) "georadius"
     7) "georadius_ro"
     8) "geosearch"
     9) "geoadd"
    10) "geodist"

    通过 ACL CAT 命令,我们可以查看到默认提供的一些命令分类,或者说是分组。然后在 ACL CAT 命令后面加上这些分类的名称,就可以看到这些分组中包含哪些命令。接下来我们试试好了,之前已经是 +@all ,也就是全部的命令权限了。

    127.0.0.1:6379> ACL SETUSER zy +@all -@dangerous -@write
    OK
    
    127.0.0.1:6379> KEYS *
    (error) NOPERM this user has no permissions to run the 'keys' command or its subcommand
    127.0.0.1:6379> SET a 2222
    (error) NOPERM this user has no permissions to run the 'set' command or its subcommand
    127.0.0.1:6379> get a
    "1111"

    现在我们 - 掉了 dangerous 和 write 这两个分类,write 分类下就是包含所有写入操作的,因此,SET 命令又没了。同时,dangerous 中包含 KEYS 命令,这时我们也没法使用 KEYS 命令了。


    此外,ACL 还有一个生成密码的命令 ACL GENPASS 。这个命令用于生成 SHA256 格式的 Hash 密码,后面的可选参数是比特位。

    127.0.0.1:6379> ACL GENPASS
    "409e9dc9709db61b310332c84078eb901d1e1bac408944a655f080a7ee5520d7"
    127.0.0.1:6379> ACL GENPASS 32
    5a56eac2
    127.0.0.1:6379> ACL GENPASS 5
    f5

    最后,再来看一下权限信息的保存。我们通过命令去创建权限用户,其实也可以通过配置文件读取并保存到配置文件中。首先要打开 redis.conf 中的 aclfile 属性并指定一个文件保存位置。如果你不指定的话,ACL SAVE 命令会报错,但是你可以通过 CONFIG REWRITE 将这些 ACL 信息保存到 redis.conf 中,这个大家可以自己试试。

    ➜ touch redis_users.acl
    
    // redis.conf
    aclfile /usr/local/etc/redis_users.acl

    然后使用 ACL SAVE 就可以保存到文件中了。当然,你也可以直接去编辑 acl 文件,或者使用 ACL LOAD 去加载某个 acl 文件。

    127.0.0.1:6379> ACL SAVE
    OK
    
    ➜ cat redis_users.acl
    user default on nopass ~* &* +@all
    user zy on ~* &* +@all -@write -@admin -keys -info -role

    GEO 地理位置

    GEO 地理位置相关的应用在什么时候崛起的?没错,就是移动互联网崛起的时候。最典型的是啥?微信中离你最近的人呀,距离多少公里,多少米的,然后加个好友开始不可描述的聊天。


    在 2016 年的时候,对于 Redis 还不太了解的我,为了解决这个距离问题,专门去用 MongoDB 来实现类似的距离计算问题,想想都晕啊,其实 GEO 在 Redis3.2 版本的时候就有了,不过话说回来,16年的时候有没有发布 3.2 ?好像我记得当时是没有类似功能的,Redis4 是 16 年 12 月发布的。


    好了,不扯这些了,反正现在 Redis 有这种功能了,就是 GEO 相关的命令。

    GEOADD key [NX|XX] [CH] longitude latitude member [longitude latitude member ...]

    127.0.0.1:6379> GEOADD bdmap 112.983037 28.198986 "51" 113.017496 28.199495 "train"
    2
    127.0.0.1:6379> get bdmap
    WRONGTYPE Operation against a key holding the wrong kind of value
    127.0.0.1:6379> ZRANGE bdmap 0 -1 withscores
    1) "51"
    2) "4050890523384816"
    3) "train"
    4) "4050890655049264"

    GEOADD 用于添加数据,上面的命令格式已经写得很清楚啦,在这里我添加的是长沙的五一广场和火车站的坐标信息。从保存的结果可以看出,GEO 其实使用的是 Sorted Set 来进行的数据保存,它的 SCORE 其实就是 Redis 处理过的一种 GeoHash 数据,这是将经纬度转换成一种独特的数字空间索引,然后通过这种数字后面的计算就比较方便啦。


    另外,我们也可以查看真实的 GeoHash 值,使用 GEOHASH 命令,这个才是真实的,上面的 SCORE 是经过 Redis 处理过的哦。

    127.0.0.1:6379> GEOHASH bdmap 51 train
    wt026vrxp80
    wt027v8cfw0

    当然,我们也可以看到原始的坐标信息。

    127.0.0.1:6379> GEOPOS bdmap 51 train
    112.9830363392829895
    28.19898708158379463
    113.01749736070632935
    28.19949402581566034

    好了,到重点了,我想知道五一广场和火车站之间的距离,怎么办?GEODIST 命令满足你的需要。

    127.0.0.1:6379> GEODIST bdmap 51 train
    3378.5059
    127.0.0.1:6379> GEODIST bdmap 51 train km
    3.3785

    GEODIST 命令后面是可以设置单位的,默认是 米 ,第二条测试命令我换成了 千米 。大家可以到地图应用上用标尺去量一下哦,长沙火车站到五一广场的直线距离真的是 3.3 公里左右。


    如果只是直线距离就太没意思了,咱们交友可是想知道一定范围内都有哪些陌生人的,比如说距离我 2 公里内都有那些人在等着加好友,这时候就可以通过 GEORADIUS 命令来获取。

    127.0.0.1:6379> GEORADIUS bdmap 112.982875 28.188591 2 km
    51
    127.0.0.1:6379> GEORADIUS bdmap 112.982875 28.188591 10 km
    51
    train
    127.0.0.1:6379> GEORADIUS bdmap 112.982875 28.188591 1 km
    
    127.0.0.1:6379> GEORADIUS bdmap 112.982875 28.188591 10 km desc
    train
    51

    GEORADIUS 是通过指定坐标和距离,返回半径范围内的符合距离条件的命令信息。当然,我们也可以直接指定某一个集合内的成员,以它的坐标为基准进行查找,使用的是 GEORADIUSBYMEMBER 命令。

    127.0.0.1:6379> GEOADD bdmap 112.982875 28.188591 nanmenkou
    (integer) 1
    
    127.0.0.1:6379> GEORADIUSBYMEMBER bdmap nanmenkou 2 km
    nanmenkou
    51
    127.0.0.1:6379> GEORADIUSBYMEMBER bdmap nanmenkou 5 km
    nanmenkou
    51
    train

    之后,在 Redis6.2 直接又出了个 GEOSEARCH 命令,用于代替上面那两个命令,这个命令更加强大。

    127.0.0.1:6379> GEOSEARCH bdmap FROMLONLAT 112.982875 28.188591 BYRADIUS 2 km ASC
    nanmenkou
    51
    
    127.0.0.1:6379> GEOSEARCH bdmap FROMLONLAT 112.982875 28.188591 BYRADIUS 2 km ASC WITHDIST
    1) 1) "nanmenkou"
       2) "0.0001"
    2) 1) "51"
       2) "1.1564"
    
    127.0.0.1:6379> GEOSEARCH bdmap FROMMEMBER nanmenkou BYRADIUS 2 km DESC
    51
    nanmenkou

    FROMLONLAT 参数表示按坐标,需要给经纬度;FROMMEMBER 则表示直接按成员。ASC 是正序,DESC 是倒序,WITHDIST 返回距离,WITHCOORD 返回坐标。


    BYRADIUS 表示的是传统的按半径画圆来找,既然有这个参数,那么是不是说明还有别的新的方式了?没错,按矩形区域来查找,高大上了吧,使用 BYBOX 就可以了。

    127.0.0.1:6379> GEOSEARCH bdmap FROMMEMBER nanmenkou BYBOX 5 5 km ASC WITHCOORD
    nanmenkou
    112.98287540674209595
    28.1885921901093468
    51
    112.9830363392829895
    28.19898708158379463

    BYBOX 需要两个距离参数,其实就是横纵帮我们从圆心坐标画个矩形出来。


    最后就是 GEOSEARCHSTORE 命令,它就是把查找到的结果保存到另一个 key 中,没啥多说的。

    127.0.0.1:6379> GEOSEARCHSTORE key1 bdmap FROMMEMBER nanmenkou BYBOX 5 5 km ASC
    2
    127.0.0.1:6379> GEOSEARCH key1  FROMMEMBER nanmenkou BYBOX 5 5 km ASC WITHCOORD
    nanmenkou
    112.98287540674209595
    28.1885921901093468
    51
    112.9830363392829895
    28.19898708158379463

    总结

    今天的命令估计用过的就比较少了吧。ACL是 Redis6 才出的,当然,现在已经是 Redis7 了,但是闲着没事升级 Redis 的企业其实并不多,毕竟大家用得最多的还是它最常用的那五大数据类型的功能。如果有做过地理位置相关服务的,估计 GEO 相关的内容还是多少会接触过一些。现在处理 GEO 的工具其实非常多了,不仅 Redis、MongoDB,大部分的搜索引擎工具也都已经支持了,并且最重要的 MySQL 也都有 GEO 类型的字段和函数了,所以怎么选择还是那句话,看具体业务情况啦。

    视频链接

    微信文章地址:https://mp.weixin.qq.com/s/xbpUsw_V_LhJJIKhNqlbrA

    B站视频地址:https://www.bilibili.com/video/BV1RW4y1X7D7

    微信视频地址:https://mp.weixin.qq.com/s/Ojsz1m0RlfJ12S1qRAUHtA

    搜索
    关注