PostgreSQL:函数中的条件语句

时间:2015-06-10 15:23:30

标签: sql postgresql stored-procedures

我一直在尝试在postgreSQL 9.4中创建一个基本的用户身份验证系统,但是一直在崩溃。我的用户表如下所示:

-- 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;

这可能吗?我完全走错了路线吗?

登录尝试失败的目的'将它设置为逐渐加长冷却期 - 例如失败尝试:

  1. 1秒
  2. 2秒
  3. 4S
  4. 787-8
  5. 16S
  6. ...

1 个答案:

答案 0 :(得分:1)

是否需要使用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;