有人用 PostgRest 和 Postgresql 成功实现了 SQL 用户管理吗?
Posted
技术标签:
【中文标题】有人用 PostgRest 和 Postgresql 成功实现了 SQL 用户管理吗?【英文标题】:anyone successfully implemented SQL User management with PostgRest and Postgresql? 【发布时间】:2020-11-04 04:05:21 【问题描述】:我正在尝试使用 PostgREST 和 PostgreSQL 实现 SQL 用户管理。 PostgRest 官方文档http://postgrest.org/en/v5.2/auth.html#sql-user-management 帮助我整理了以下内容:
create schema if not exists basic_auth;
create table if not exists
basic_auth.users (
email text primary key check ( email ~* '^.+@.+\..+$' ),
pass text not null check (length(pass) < 512),
role name not null check (length(role) < 512)
);
create table if not exists
basic_auth.jwt_token (
);
create or replace function
basic_auth.check_role_exists() returns trigger as $$
begin
if not exists (select 1 from pg_roles as r where r.rolname = new.role) then
raise foreign_key_violation using message =
'unknown database role: ' || new.role;
return null;
end if;
return new;
end
$$ language plpgsql;
drop trigger if exists ensure_user_role_exists on basic_auth.users;
create constraint trigger ensure_user_role_exists
after insert or update on basic_auth.users
for each row
execute procedure basic_auth.check_role_exists();
create extension if not exists pgcrypto;
create or replace function
basic_auth.encrypt_pass() returns trigger as $$
begin
if tg_op = 'INSERT' or new.pass <> old.pass then
new.pass = crypt(new.pass, gen_salt('bf'));
end if;
return new;
end
$$ language plpgsql;
drop trigger if exists encrypt_pass on basic_auth.users;
create trigger encrypt_pass
before insert or update on basic_auth.users
for each row
execute procedure basic_auth.encrypt_pass();
create or replace function
basic_auth.user_role(email text, pass text) returns name
language plpgsql
as $$
begin
return (
select role from basic_auth.users
where users.email = user_role.email
and users.pass = crypt(user_role.pass, users.pass)
);
end;
$$;
-- login should be on your exposed schema
create or replace function
login(email text, pass text) returns basic_auth.jwt_token as $$
declare
_role name;
result basic_auth.jwt_token;
begin
-- check email and password
select basic_auth.user_role(email, pass) into _role;
if _role is null then
raise invalid_password using message = 'invalid user or password';
end if;
select sign(
row_to_json(r), 'super_secret'
) as token
from (
select _role as role, login.email as email,
extract(epoch from now())::integer + 60*60 as exp
) r
into result;
return result;
end;
$$ language plpgsql;
-- sacred, we simply choose them for clarity
create role anon;
create role authenticator noinherit login;
grant usage on schema public to authenticator;
grant anon to authenticator;
grant usage on schema public, basic_auth to anon;
grant select on table pg_authid, basic_auth.users to anon;
grant execute on function login(text,text) to anon;
当我尝试发出 POST 请求时:
localhost:3000/rpc/login "email": "foo@bar.com", "pass": "foobar"
"hint": "No function matches the given name and argument types. You might need to add explicit type casts.",
"details": null,
"code": "42883",
"message": "function public.login() does not exist"
我认为这是权限问题!我不确定我错过了什么。
【问题讨论】:
在您的 .conf 文件中,db-schema
的值是多少?我认为该架构是需要创建函数 login()
的地方。
它的公共和 login() 在公共模式中我可以看到它!
@haytham 可能是关于如何处理对server 的 POST 请求的问题。我在答案中添加了一个示例,您可以尝试使用 curl(有关更多信息,请参阅 this)。
function public.login() does not exist
消息实际上意味着没有参数被传递给函数。确保正确获取 POST 数据。
下面的答案是正确的!只需要实现正确的权限。
【参考方案1】:
尝试在公共架构中定义登录功能
-- change this code
-- login should be on your exposed schema
create or replace function
login(email text, pass text) returns basic_auth.jwt_token as $$
-- with
-- login should be on your exposed schema
create or replace function
public.login(email text, pass text) returns basic_auth.jwt_token as $$
尝试使用curl
发送Send POST
curl --header "Content-Type: application/json" \
--request POST \
--data ' "email": "foo@bar.com", "pass": "foobar" ' \
localhost:3000/rpc/login
【讨论】:
虽然功能在那里,但仍然找不到!以上是关于有人用 PostgRest 和 Postgresql 成功实现了 SQL 用户管理吗?的主要内容,如果未能解决你的问题,请参考以下文章
PostgreSQL神器之PostgREST(macos版本使用)