我在Sybase和SQL Server工作多年之后开始了PostgreSQL项目,并且对它的怪癖很新,但到目前为止给人留下了深刻的印象。
我写了一个返回OUT参数的小函数。我传入一个明确的密码,该函数返回加密的密码和一个盐。这是:
CREATE OR REPLACE FUNCTION iSecGenPwdSalt(pwdin text, out salt text, out userpassword text)
AS
$BODY$
DECLARE
BEGIN
-- Generate a salt...
salt = gen_salt('bf', 10);
-- Now generate the password hash...
userpassword = crypt(pwdin, salt);
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION iSecGenPwdSalt(text, out text , out text ) OWNER TO postgres;
我想在触发器中调用此函数并使用这些值填充我的密码和salt列,但我无法理解语法。我在主题上尝试了多种变体,但我仍然遇到问题。
select salt, userpassword from iSecGenPwdSalt('mymagicpassword');
很好地返回它的结果,所以我想调用这个函数并将结果输入到触发器中的一对变量中,这样我就可以赋值了。
这是我的代码:
SELECT usersalt=salt, userpwd=userpassword
FROM iSecGenPwdSalt(NEW.systemuserpassword);
我得到的错误是:
错误:查询没有结果数据的目的地 提示:如果要放弃SELECT的结果,请改用PERFORM。 语境:SQL语句中的PL / pgSQL函数“isec_trg_systemuser”第13行
因此,简单地将一对变量分配给从触发器中的OUT参数派生的结果集会让我感到悲伤。
答案 0 :(得分:1)
这不是你要问的问题的答案,但最近我不得不做类似的事情,我用视图和规则而不是触发器来做。我希望这是有帮助的,尽管不是真正回答你直接提出的问题。
这是我的用户表和视图:
CREATE TABLE users_t (
username VARCHAR(16) PRIMARY KEY,
email VARCHAR UNIQUE,
password CHAR(60),
salt CHAR(29)
);
CREATE VIEW users AS SELECT username, email, '********'::varchar AS password FROM users_t;
插入规则负责生成salt值:
CREATE RULE users_insert_rule AS ON INSERT TO users DO INSTEAD
INSERT INTO users_t (username, email, password, salt)
SELECT new.username, new.email, crypt(new.password, salt.salt), salt.salt
FROM (SELECT gen_salt('bf') as salt) salt
RETURNING username, email, '********'::varchar;
为了完整性,我包括更新和删除规则,即使它们不是特别相关:
CREATE RULE users_update_rule AS ON UPDATE TO users DO INSTEAD
UPDATE users_t
SET
username = new.username,
email = new.email,
password = crypt(new.password, salt)
RETURNING username, email, '********'::varchar;
CREATE RULE users_delete_rule AS ON DELETE TO users DO INSTEAD
DELETE FROM users_t WHERE username = old.username
RETURNING username, email, '********'::varchar;
然后我编写了一个认证功能,负责使用salt:
CREATE OR REPLACE FUNCTION authenticate(varchar, varchar) RETURNS setof users AS $$
SELECT * FROM users
WHERE username =
(SELECT username FROM users_t
WHERE username = $1 AND crypt($2, salt) = password)
$$ LANGUAGE sql;
因此,您可以通过查询SELECT * FROM authenticate('username', 'password');
“登录”,并通过插入users
视图来创建用户。您可以设置权限,使您具有可以查看用户视图但不能查看基础users_t表的非特权角色。通过这种方式,您可以轻松地使用salted密码与users表进行交互,而无需在应用程序中处理salt。
答案 1 :(得分:1)
在您的具体情况下,我认为您可以将SELECT INTO
语句与多列一起使用:
CREATE OR REPLACE FUNCTION userAuth_insert_f() RETURNS TRIGGER AS $$
BEGIN
SELECT INTO NEW.usersalt, NEW.userpwd
salt, userpassword FROM iSecGenPwdSalt(NEW.systemuserpassword);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
完整示例(使用pgcrypto
contrib模块):
DROP TABLE IF EXISTS userAuth;
CREATE TABLE userAuth (
id serial,
systemuserpassword text,
usersalt text,
userpwd text
);
CREATE OR REPLACE FUNCTION iSecGenPwdSalt
(pwdin text, OUT salt text, OUT userpassword text)
AS $$ BEGIN
salt = gen_salt('bf', 10);
userpassword = crypt(pwdin, salt);
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS userAuth_insert_t ON userAuth;
CREATE TRIGGER userAuth_insert_t
BEFORE INSERT ON userAuth
FOR EACH ROW
EXECUTE PROCEDURE userAuth_insert_f();
调用:
=>INSERT INTO userAuth (systemuserpassword) VALUES ('mymagicpassword');
INSERT 0 1
=>SELECT usersalt, userpwd FROM userauth;
usersalt | userpwd
-------------------------------+---------------------------------------------------
$2a$10$7FqU5a/DrM.CWGlQPlGz6e | $2a$10$7FqU5a/DrM.CWGlQPlGz6eLjuN3UTwh/hlgxTnogS..
(1 row)