预计阅读时间:5分钟

目录直通车

前言

一、如何实现权限验证?

1、 后台JWT生成key

 (1) 新增用户 (Add a Trusted User)

(2) 加密处理(Make a Secret)

(3) 制定token(Sign a Token)

(4) HTTP请求

(5) 设置token的到期时间

2、 前台与后台结合实现

这样真的安全吗,如果请求被伪造怎么办?


前言

最近在做一个工厂的项目,在这个项目里面需要给用户设置一些权限,比如说普通员工只能录入数据不能修改、普通管理员可以查看和修改、超级管理员可以给其他用户设置有哪些权限。以下内容是我们团队完成权限验证之后的浓缩总结。PostgREST不知道是啥的话,还是点击这里补脑吧!(官方文档实在看不懂的话.......关于PostgREST的中文文档,我们团队已翻译处理,后续也会放在文末分享给大家。)

一、如何实现权限验证?

(参考PostgREST官方文档JWT部分:http://postgrest.org/en/v5.1/auth.html#jwt-generation如果下面的方案解决不了您的问题请参考其它方案请回来参考http://postgrest.org/en/v5.1/tutorials/tut1.html#tutorial-1-the-golden-key

这个项目的验证机制的核心是在后台生成一个带有权限的key,前台只是负责发送key与后台的key比对,我不想误导大家,因为我之前被别人的文章误导之后久久不能释怀......,所以请看下方原话:

客户端使用JSON Web Tokens通过API进行身份验证。这些是JSON对象,使用仅为我们和服务器所知的密码进行加密签名。由于客户端不知道密码,因此无法篡改其令牌的内容。PostgREST将检测伪造的令牌并拒绝它们。

那么问题来了,如果有人抓数据包,岂不是很容易就什么都看到了?所以需要加密。

1、 后台JWT生成key

这个key分为三部分,前两个部分系统生成,在第三个secret的部分。请注意这里指的不是用户的密码,当时我看了一些博文导致我以为token写死的不能变。然而,这个secret的部分是自己可以随意放入的字符串,这样的加密方式可以说是非常安全。如果您已经明白了,看完下面这张图就可以直接跳过了。

具体实现

(原文链接:http://postgrest.org/en/v5.1/tutorials/tut1.html#step-1-add-a-trusted-user

 (1) 新增用户 (Add a Trusted User)

在PostgreSQL数据库中创建了一个web_anon角色,用于执行匿名Web请求。让我们todo_user为使用API,进行身份验证的用户调用一个角色。此角色将有权赋予权限列表执行任何操作。

//创建角色不允许登陆
create role todo_user nologin;    
//赋予角色与postgres用户	
grant todo_user to postgres;	
 //schema api允许todo_user查找该Schema下的对象
grant usage on schema api to todo_user;   
 //单表赋予todo_user角色对api.todos表所有权限
grant all on api.todos to todo_user;     
//赋予todo_user 对于当前api下的所有表的所有权限
//grant select on ALL tables in schema api to web_anon ;   
//查询此表序列号的权限也就是 序列号自动增长的权限
grant usage, select on sequence api.todos_id_seq to todo_user;  

(2) 加密处理(Make a Secret)

客户端使用JSON Web Tokens通过API进行身份验证。这些是JSON对象,使用仅为我们和服务器所知的密码进行加密签名。由于客户端不知道密码,因此无法篡改其令牌的内容。PostgREST将检测伪造的令牌并拒绝它们。

让我们创建一个密码并将其提供给PostgREST。想想一个很好的长的,或使用工具来生成它。您的密码长度必须至少为32个字符

我们的服务器是:Linux 7

[root@localhost ~]# openssl rand 32 -base64

得到下面这串加密后的字符串:qHH/CeK+w3gqSOZjZJyuon4n7ptaQ+2TarNh7r7BYKM=

 接着打开 tutorial.conf 文件,把这串加密的字符串新增一行写进去。

# PASSWORD MUST BE AT LEAST 32 CHARS LONG
# add this line to tutorial.conf:

#jwt-secret = "<the password you made>"
jwt-secret = "qHH/CeK+w3gqSOZjZJyuon4n7ptaQ+2TarNh7r7BYKM="

#如果启用了secret base64 encoded 
#请把下面设置为ture默认为false 本实例中设置的
#secret-is-base64 = true

然后重启PostgREST服务器,一定不要忘记了。

(3) 制定token(Sign a Token)

在JWT的官网创建一个会话测试:https://jwt.io

(4) HTTP请求

现在回到服务器终端,让我们curl来添加一个行记录。该请求将包含一个包含身份验证令牌的HTTP标头。

#export TOKEN="<paste token here>"
export TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidG9kb191c2VyIn0.8qw7X2-98Gaua0d5AljE8qaBWd-LFBlCdLVQ5hOnNyA"
curl http://localhost:3000/todos -X POST \
     -H "Authorization: Bearer $TOKEN"   \
     -H "Content-Type: application/json" \
     -d '{"task": "learn how to auth"}'

 紧接着通过一个patch请求将done设置为true。

curl http://localhost:3000/todos -X PATCH \
     -H "Authorization: Bearer $TOKEN"    \
     -H "Content-Type: application/json"  \
     -d '{"done": true}'

服务器端完成配置后。在postgREST里发送一个如下的json包请求给服务器测试一波。

curl http://localhost:3000/todos
[
  {
    "id": 1,
    "done": true,
    "task": "finish tutorial 0",
    "due": null
  },
  {
    "id": 2,
    "done": true,
    "task": "pat self on back",
    "due": null
  },
  {
    "id": 3,
    "done": true,
    "task": "learn how to auth",
    "due": null
  }
]

(5) 设置token的到期时间

原文如下:

Currently our authentication token is valid for all eternity. The server, as long as it continues using the same JWT password, will honor the token.

It’s better policy to include an expiration timestamp for tokens using the exp claim. This is one of two JWT claims that PostgREST treats specially.

目前token永久有效,只要服务器继续使用相同的JWTSecret,它就会使用相同的token,所以就希望能够设置这个token到期的时间,需要使用exp来声明时间戳给这个token。

现在在数据库运行下面这条命令来设置到期时间:

select extract(epoch from now() + '5 minutes'::interval) :: integer;

再回到发送https://jwt.io 以下payload:

{
  "role": "todo_user",
  "exp": <computed epoch value>
}

把之前的token复制保存到一个新的变量里面,便于复制之后重新向服务器发送请求作为对比。

as $$
begin
  if current_setting('request.jwt.claim.email', true) =
     'disgruntled@mycompany.com' then
    raise insufficient_privilege
      using hint = 'Nope, we are on to you';
  end if;
end
$$;

接下来在tutorial.conf的文件里面添加下面一行指定新功能

pre-request = "auth.check_token"

完成之后,请不要忘记重启PostgREST。下面验证一下之前保存下来的token。

# 这个可以正常请求

curl http://localhost:3000/todos \
     -H "Authorization: Bearer $TOKEN"

# 这个请求失败

curl http://localhost:3000/todos \
     -H "Authorization: Bearer $WAYWARD_TOKEN"

失败之后,服务器会返回以下信息:

{
  "hint": "Nope, we are on to you",
  "details": null,
  "code": "42501",
  "message": "insufficient_privilege"
}

 

2、 前台与后台结合实现

前台Vue无非就是route路由控制。我这里实现的方式是,用户每一次的操作都会做一次校验(也就是key与服务器的key比对),前端的话可以减轻工作量,而且也很安全。

这样真的安全吗,如果请求被伪造怎么办?

这个key分为三个部分,有两个部分是写死的,secret这个部分可以随机给,然后组合成为一段字符串。所以,在用户登录的时候才给用户生成一个他对应权限的key,然后销毁。每一次登录和每一次操作都会重新生成一次key,每一次都会与后台的key比对。

源码的话,一般我都会免费分享给大家,但考虑到同某央企工厂签过保密协议,这里就不提供给大家了,还望见谅。

PostgREST中文参考文档 ,提取码: rnbn

 

 

 

 

 

Logo

前往低代码交流专区

更多推荐