PostgreSQL:函数中的条件语句
PostgreSQL: conditional statements in functions
我一直在尝试在 postgreSQL 9.4 中创建一个基本的用户身份验证系统,但一直没有成功。我的用户 table 看起来像这样:
-- Users table
CREATE TABLE users (
user_id SERIAL NOT NULL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT NOT NULL,
password TEXT NOT NULL,
failed_login_attempts INT NOT NULL DEFAULT 0
CONSTRAINT positive_login_attempts CHECK (failed_login_attempts >= 0),
last_failed_login_attempt TIMESTAMP NULL,
UNIQUE(email),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL,
deleted_at TIMESTAMP NULL
);
这些函数工作正常:
-- check to see if a user exists
CREATE OR REPLACE FUNCTION user_exists (auth_email VARCHAR(254))
RETURNS SETOF users AS $$
SELECT *
FROM users
WHERE email = auth_email
$$ LANGUAGE SQL;
-- authenticates a user against the system
CREATE OR REPLACE FUNCTION authenticate_user (auth_email VARCHAR(254), auth_password VARCHAR(72))
RETURNS SETOF users AS $$
SELECT *
FROM users
WHERE email = auth_email
AND password = crypt(auth_password, password))
$$ LANGUAGE SQL;
但是,当我尝试将这些结合起来时,我的脸就垮了。在半伪代码中,我想做的是:
-- login function
CREATE OR REPLACE FUNCTION user_login (auth_email VARCHAR(254), auth_password VARCHAR(72)) RETURNS SETOF users AS $$
IF EXISTS (SELECT COUNT(*) FROM user_exists(auth_email))
IF EXISTS (SELECT COUNT(*) FROM authenticate_user (auth_email, auth_password))
-- set the failed_login_attempts value to 0
-- set the last failed login attempt as NULL
-- return the user details
ELSE
-- increment the failed_login_attempts value
-- set the last failed login attempt as the current time
-- return nothing
END IF;
ELSE
-- return nothing
END IF;
$$ LANGUAGE SQL;
这可能吗?我是否完全走错了路线?
'failed login attempts' 的目的是将其设置为逐渐延长冷静期 - 例如失败的尝试:
- 1秒
- 2秒
- 4s
- 8s
- 16s
- ...
是否要求使用SQL
语言编写函数?
如果您接受 PLPGSQL
.
,则有 PLPGSQL
程序的解决方案
CREATE OR REPLACE FUNCTION user_login (auth_email VARCHAR(254), auth_password VARCHAR(72))
RETURNS SETOF users AS
$$
DECLARE
found_user users;
BEGIN
SELECT u.*
FROM users u
WHERE u.email=auth_email
INTO found_user;
-- Check password here using your algorithm
IF found_user.password = auth_password THEN
RETURN NEXT found_user;
RETURN;
END IF;
UPDATE users SET
failed_login_attempts = failed_login_attempts + 1
, last_failed_login_attempt = now()
WHERE user_id = found_user.user_id;
END;
$$
LANGUAGE plpgsql;
我一直在尝试在 postgreSQL 9.4 中创建一个基本的用户身份验证系统,但一直没有成功。我的用户 table 看起来像这样:
-- Users table
CREATE TABLE users (
user_id SERIAL NOT NULL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT NOT NULL,
password TEXT NOT NULL,
failed_login_attempts INT NOT NULL DEFAULT 0
CONSTRAINT positive_login_attempts CHECK (failed_login_attempts >= 0),
last_failed_login_attempt TIMESTAMP NULL,
UNIQUE(email),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL,
deleted_at TIMESTAMP NULL
);
这些函数工作正常:
-- check to see if a user exists
CREATE OR REPLACE FUNCTION user_exists (auth_email VARCHAR(254))
RETURNS SETOF users AS $$
SELECT *
FROM users
WHERE email = auth_email
$$ LANGUAGE SQL;
-- authenticates a user against the system
CREATE OR REPLACE FUNCTION authenticate_user (auth_email VARCHAR(254), auth_password VARCHAR(72))
RETURNS SETOF users AS $$
SELECT *
FROM users
WHERE email = auth_email
AND password = crypt(auth_password, password))
$$ LANGUAGE SQL;
但是,当我尝试将这些结合起来时,我的脸就垮了。在半伪代码中,我想做的是:
-- login function
CREATE OR REPLACE FUNCTION user_login (auth_email VARCHAR(254), auth_password VARCHAR(72)) RETURNS SETOF users AS $$
IF EXISTS (SELECT COUNT(*) FROM user_exists(auth_email))
IF EXISTS (SELECT COUNT(*) FROM authenticate_user (auth_email, auth_password))
-- set the failed_login_attempts value to 0
-- set the last failed login attempt as NULL
-- return the user details
ELSE
-- increment the failed_login_attempts value
-- set the last failed login attempt as the current time
-- return nothing
END IF;
ELSE
-- return nothing
END IF;
$$ LANGUAGE SQL;
这可能吗?我是否完全走错了路线?
'failed login attempts' 的目的是将其设置为逐渐延长冷静期 - 例如失败的尝试:
- 1秒
- 2秒
- 4s
- 8s
- 16s
- ...
是否要求使用SQL
语言编写函数?
如果您接受 PLPGSQL
.
PLPGSQL
程序的解决方案
CREATE OR REPLACE FUNCTION user_login (auth_email VARCHAR(254), auth_password VARCHAR(72))
RETURNS SETOF users AS
$$
DECLARE
found_user users;
BEGIN
SELECT u.*
FROM users u
WHERE u.email=auth_email
INTO found_user;
-- Check password here using your algorithm
IF found_user.password = auth_password THEN
RETURN NEXT found_user;
RETURN;
END IF;
UPDATE users SET
failed_login_attempts = failed_login_attempts + 1
, last_failed_login_attempt = now()
WHERE user_id = found_user.user_id;
END;
$$
LANGUAGE plpgsql;