MYSQL存儲過程實現用戶登錄


MYSQL存儲過程實現用戶登錄

CREATE DEFINER=`root`@`%` PROCEDURE `uc_session_login`(
    IN `_email` VARCHAR(50),
    IN `_pwdmd5` CHAR(32)
)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
    #密鑰表
    DECLARE _keyid INT(10)UNSIGNED;
    DECLARE _secretkey CHAR(32);
    #登錄表
    DECLARE _uid INT(10)UNSIGNED;
    DECLARE _username VARCHAR(50);
    DECLARE _password CHAR(32);
    DECLARE _salt CHAR(6);
    #地址記錄表
    DECLARE _failedlogins INT(10)UNSIGNED;
    #與字段無關的輸入
    DECLARE failedlogins_max INT(10)UNSIGNED DEFAULT 1;#密碼錯誤次數上限
    DECLARE failedlogins_timeout INT(10)UNSIGNED DEFAULT 2;#時間范圍內清零計數
    DECLARE failedlogins_unlocktime INT(10)UNSIGNED DEFAULT 10;#密碼錯誤次數超限后鎖定時間
    DECLARE secretkey2 VARCHAR(32)DEFAULT IFNULL(@secretkey2,'');
    DECLARE useripaddress VARCHAR(39)DEFAULT@ipaddress;
    #與字段無關的輸出
    DECLARE json JSON DEFAULT'{}';
    loop0:LOOP
        #首先判斷IP地址是否已被禁止嘗試密碼
        DELETE FROM uc_session_ipaddress WHERE beforedel<CURRENT_TIMESTAMP();#刪除較早的IP
        SELECT failedlogins INTO _failedlogins FROM uc_session_ipaddress WHERE ipaddress=useripaddress;
        IF _failedlogins>failedlogins_max THEN
            SELECT -11 AS errno,'您嘗試密碼錯誤過多,請稍候再試' AS message;
            LEAVE loop0;
        END IF;
        SELECT uid,username,`password`,salt INTO _uid,_username,_password,_salt FROM uc_members WHERE email=_email;
        IF ISNULL(_uid) THEN SELECT -1 AS errno,'您輸入的E-Mail尚未注冊' AS message;LEAVE loop0;END IF;
        IF MD5(CONCAT(_pwdmd5,_salt))<>_password THEN
            SELECT -2 AS errno,'您輸入的密碼錯誤' AS message;
            INSERT INTO uc_session_log(uid,ipaddress,errno,error)VALUES(_uid,useripaddress,-2,'登錄密碼錯誤');
            IF ISNULL(_failedlogins) THEN
                INSERT INTO uc_session_ipaddress(ipaddress,failedlogins,beforedel)VALUES(useripaddress,1,TIMESTAMPADD(SECOND,failedlogins_timeout,CURRENT_TIMESTAMP()));
            ELSE
                UPDATE uc_session_ipaddress SET failedlogins=_failedlogins+1,beforedel=TIMESTAMPADD(SECOND,failedlogins_unlocktime,CURRENT_TIMESTAMP()) WHERE ipaddress=useripaddress;
            END IF;
            LEAVE loop0;
        END IF;
        #登錄校驗已通過,開始取得secretkey並出hmac
        SELECT id,secretkey INTO _keyid,_secretkey FROM uc_session_key WHERE started<CURRENT_TIMESTAMP() AND expired>CURRENT_TIMESTAMP() ORDER BY expired DESC LIMIT 1;
        IF ISNULL(_keyid) OR ISNULL(_secretkey) THEN SELECT -3 AS errno,'secretkey獲取失敗' AS message;LEAVE loop0;END IF;
        SET json=JSON_SET(json,'$.logintime',UNIX_TIMESTAMP(CURRENT_TIMESTAMP(6)));
        SET json=JSON_SET(json,'$.loginip',useripaddress);
        SET json=JSON_SET(json,'$.uid',_uid);
        SET json=JSON_SET(json,'$.email',_email);
        SET json=JSON_SET(json,'$.username',_username);
        SET json=JSON_SET(json,'$.password',_password);
        SET json=JSON_SET(json,'$.salt',_salt);
        SELECT json,_keyid AS keyid,uc_session_hmacsha1(CONCAT(_secretkey,secretkey2),json)AS hmacsha1;
        INSERT INTO uc_session_log(uid,ipaddress,errno,error)VALUES(_uid,useripaddress,0,'登錄成功');
        LEAVE loop0;
    END LOOP;
END

 第2版

CREATE DEFINER=`root`@`%` FUNCTION `uc_session_login`(
    `reqjson` JSON,
    `srvjson` JSON
)
RETURNS json
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'UC的用戶登錄,返回JSON'
BEGIN
    #調用例子
    #SELECT `uc_session_login`(JSON_OBJECT('appid',1,'email','test@firadio.com','pwdmd5',MD5('test')),JSON_OBJECT('ipaddress','1.1.1.1'))json
    DECLARE retjson JSON DEFAULT JSON_OBJECT('error',0);
    #密鑰表
    DECLARE _keyid INT(10)UNSIGNED;
    DECLARE _secretkey CHAR(32);
    #登錄表
    DECLARE _uid INT(10)UNSIGNED;
    DECLARE _username VARCHAR(50);
    DECLARE _password CHAR(32);
    DECLARE _salt CHAR(6);
    #地址記錄表
    DECLARE _failedlogins INT(10)UNSIGNED;
    DECLARE _resetwhen TIMESTAMP;#計次重置時間
    #與字段無關的輸入
    DECLARE failedlogins_max INT(10)UNSIGNED DEFAULT 3;#密碼錯誤次數上限
    DECLARE failedlogins_timeout INT(10)UNSIGNED DEFAULT 20;#時間范圍內清零計數
    DECLARE failedlogins_unlocktime INT(10)UNSIGNED DEFAULT 10;#密碼錯誤次數超限后鎖定時間
    #DECLARE srvjson JSON DEFAULT IFNULL(CAST(@srvjson AS CHAR),JSON_OBJECT());#已由會話變量改為函數的參數
    DECLARE secretkey2 VARCHAR(32)DEFAULT IFNULL(srvjson->>'$.secretkey2','');#二級密鑰
    DECLARE useripaddress VARCHAR(39)DEFAULT srvjson->>'$.ipaddress';#用戶IP地址
    DECLARE req_appid INT UNSIGNED DEFAULT reqjson->>'$.appid';
    DECLARE req_email VARCHAR(50)DEFAULT reqjson->>'$.email';
    DECLARE req_pwdmd5 CHAR(32)DEFAULT reqjson->>'$.pwdmd5';
    #與字段無關的輸出
    DECLARE userjson JSON DEFAULT JSON_OBJECT();
    #首先判斷IP地址是否已被禁止嘗試密碼
    #DELETE FROM uc_session_ipaddress WHERE resetwhen<CURRENT_TIMESTAMP();#刪除較早的IP
    UPDATE uc_session_ipaddress SET failedlogins=0 WHERE resetwhen<CURRENT_TIMESTAMP();#重置已超時的計數
    SET _failedlogins=0;
    SELECT failedlogins,resetwhen INTO _failedlogins,_resetwhen FROM uc_session_ipaddress WHERE ipaddress=useripaddress FOR UPDATE;
    IF _failedlogins>=failedlogins_max THEN
        RETURN JSON_SET(retjson,'$.errno',-11,'$.message',CONCAT('由於密碼錯誤次數過多,已被鎖定。解鎖時間:',_resetwhen));
    END IF;
    SELECT uid,username,`password`,salt INTO _uid,_username,_password,_salt FROM uc_members WHERE email=req_email FOR UPDATE;
    IF ISNULL(_uid) THEN RETURN JSON_SET(retjson,'$.errno',-1,'$.message','您輸入的E-Mail尚未注冊');END IF;
    IF MD5(CONCAT(req_pwdmd5,_salt))<>_password THEN
        INSERT INTO uc_session_loginlog(appid,uid,ipaddress,errno,error)VALUES(req_appid,_uid,useripaddress,-2,'登錄密碼錯誤');
        SET @curfailed=_failedlogins+1;#當前計數值
        SET @resetwhen_timeout=TIMESTAMPADD(SECOND,failedlogins_timeout,CURRENT_TIMESTAMP());#清零計數的時間
        IF ISNULL(_resetwhen) THEN#記錄為空只能新增
            INSERT INTO uc_session_ipaddress SET ipaddress=useripaddress,failed=CURRENT_TIMESTAMP(),failedlogins=1,faileduid=_uid,resetwhen=@resetwhen_timeout ON DUPLICATE KEY UPDATE failed=VALUES(failed),failedlogins=VALUES(failedlogins),faileduid=VALUES(faileduid),resetwhen=VALUES(resetwhen);
        ELSEIF _failedlogins=0 THEN
            #記錄第一次密碼錯誤,並設置新的計數超時時間
            UPDATE uc_session_ipaddress SET failed=CURRENT_TIMESTAMP(),failedlogins=@curfailed,faileduid=_uid,resetwhen=@resetwhen_timeout WHERE ipaddress=useripaddress;
        ELSE
            UPDATE uc_session_ipaddress SET failed=CURRENT_TIMESTAMP(),failedlogins=@curfailed,faileduid=_uid,resetwhen=TIMESTAMPADD(SECOND,failedlogins_unlocktime,CURRENT_TIMESTAMP()) WHERE ipaddress=useripaddress;
        END IF;
        IF @curfailed>=failedlogins_max THEN
            RETURN JSON_SET(retjson,'$.errno',-3,'$.message',CONCAT('由於密碼錯誤次數已達',failedlogins_max,'次,現已被鎖定',failedlogins_unlocktime,''));
        END IF;
        RETURN JSON_SET(retjson,'$.errno',-2,'$.message',CONCAT('您已輸錯',@curfailed,'次密碼,如再錯',failedlogins_max-@curfailed,'次將被鎖定',failedlogins_unlocktime,''));
    END IF;
    #登錄校驗已通過
    #開始取得secretkey並出hmac
    SELECT id,secretkey INTO _keyid,_secretkey FROM uc_session_keycenter WHERE appid=req_appid AND expired>CURRENT_TIMESTAMP() LIMIT 1;
    IF ISNULL(_keyid) OR ISNULL(_secretkey) THEN RETURN JSON_SET(retjson,'$.errno',-4,'$.message','secretkey獲取失敗');END IF;
    SET userjson=JSON_SET(userjson,'$.logintime',UNIX_TIMESTAMP(CURRENT_TIMESTAMP()),'$.loginip',useripaddress);
    SET userjson=JSON_SET(userjson,'$.uid',_uid,'$.email',req_email,'$.username',_username,'$.password',_password,'$.salt',_salt);
    IF ISNULL(_resetwhen) THEN#記錄為空只能新增
        INSERT INTO uc_session_ipaddress SET ipaddress=useripaddress,failedlogins=0,succeed=CURRENT_TIMESTAMP(),succeeduid=_uid,succeedlogins=1 ON DUPLICATE KEY UPDATE failedlogins=VALUES(failedlogins),succeed=VALUES(succeed),succeeduid=VALUES(succeeduid),succeedlogins=succeedlogins+1;
    ELSE
        UPDATE uc_session_ipaddress SET failedlogins=0,succeed=CURRENT_TIMESTAMP(),succeeduid=_uid,succeedlogins=succeedlogins+1 WHERE ipaddress=useripaddress;
    END IF;
    INSERT INTO uc_session_loginlog(appid,uid,ipaddress,errno,error)VALUES(req_appid,_uid,useripaddress,0,'登錄成功');
    SET retjson=JSON_SET(retjson,'$.userjson',CAST(userjson AS CHAR),'$.keyid',_keyid);
    SET retjson=JSON_SET(retjson,'$.hmacsha1',uc_session_hmacsha1(CONCAT(_secretkey,secretkey2),retjson->>'$.userjson'));
    RETURN JSON_SET(retjson,'$.errno',0,'$.message','登錄成功');
END

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM