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

MYSQL存储过程实现用户登录的更多相关文章

  1. 希赛网 > 问答 > 数据库 > MySQL数据库 > MySQL的管理与维护 > MySql开启远程用户登录GRANTALLPRIVILEGESON*.*TO'root'@'%'I MySql开启远程用户登录GRANTALLPRIVILEGESON*.*TO'root'@'%'I

    MySql开启远程用户登录 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'huawei' WITH GRANT OPTION; FL ...

  2. MySql开启远程用户登录GRANTALLPRIVILEGESON*.*TO'root'@'%'I MySql开启远程用户登录GRANTALLPRIVILEGESON*.*TO'root'@'%'I

    MySql开启远程用户登录 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'huawei' WITH GRANT OPTION; FL ...

  3. Java Spring+Mysql+Mybatis 实现用户登录注册功能

    前言: 最近在学习Java的编程,前辈让我写一个包含数据库和前端的用户登录功能,通过看博客等我先是写了一个最基础的servlet+jsp,再到后来开始用maven进行编程,最终的完成版是一个 Spri ...

  4. MySQL存储过程:用户授权量

    写这些脚本需求放缓的调查记录到数据库,方便观看. 1. 因为默认mysql.slow_log表使用csv数据引擎,该数据不支持指数,因此,有必要改变MyISAM发动机.和query_time字段索引, ...

  5. Yii Framework2.0开发教程(10)配合mysql数据库实现用户登录

    1.首先在mysql创建一个存用户的表格 create table test_user ( user_id bigint(20) unsigned not null auto_increment co ...

  6. MySQL授权远程用户登录权限

    1 举例子,建数据库,然后 赋予用户远程访问的所有权限,最后刷新权限 create database cmf DEFAULT CHARACTER SET utf8; grant all on cmf. ...

  7. MySQL使用root用户授权出现错误ERROR 1045 (28000) at line 2: Access denied for user 'root'@'%' (using password: YES)解决办法

    参考:https://blog.csdn.net/open_data/article/details/42873827 使用MySQL的root用户登录出现错误提示 ERROR 1045 (28000 ...

  8. MySQL误删root用户导致无法登陆解决方法

    测试环境   删除前 mysql> select user,host,password from mysql.user; +------+-----------+---------------- ...

  9. mysql颠覆实战笔记(三)-- 用户登录(二):保存用户操作日志的方法

    版权声明:笔记整理者亡命小卒热爱自由,崇尚分享.但是本笔记源自www.jtthink.com(程序员在囧途)沈逸老师的<web级mysql颠覆实战课程 >.如需转载请尊重老师劳动,保留沈逸 ...

随机推荐

  1. matplotlib各图形绘制

    2D图形 import numpy as np import pandas as pd from pandas import Series,DataFrame import matplotlib.py ...

  2. linux 安装配置zookeeper

    1.什么是zookeeper ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用 ...

  3. css3的transform-origin配合scale,控制动画,实现各种hover效果

    1.底部画线,从左边开始,右边结束 html: <div class="silde-txt">底部划线</div> css: <style>.s ...

  4. windows下《Go Web编程》之Go环境配置和安装

    <Go Web编程>笔者是基于unix下讲述的,作为入门练手,我选择在windows下开发,全程按照目录进行... 一.安装 windows下需要安装MinGW,通过MinGW安装gcc支 ...

  5. codeblock不能调试

    问题:codeblock  不能调试,如下图: 解决方法: 首先,项目的保存路径不能是中文路径. 其次,必须创建工程. 最后,build选项里select target选成debug codebloc ...

  6. Python简介(一)

    1.Python简介 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC ...

  7. java中的线程问题是(四)——线程同步问题

    多线程的并发,给我们编程带来很多好处,完成更多更有效率的程序.但是也给我们带来线程安全问题. 解决问题的关键就是要保证容易出问题的代码的原子性,所谓原子性就是指:当a线程在执行某段代码的时候,别的线程 ...

  8. tp5阿里云短信发送

    到阿里云下载php版demo,下完整版的,不是轻量级的; 框架  :TP5 把下载下来的文件放到extend里面 文件名:alimsg 里面的文件 import('alimsg.api_demo.Sm ...

  9. clearfix 用法

    如果有一个DIV作为外部容器,内部的DIV如果设置了float样式,则外部的容器DIV因为内部没有 clear,导致不能被撑开.看下面的例子:Div布局如下:Css代码如下:.out{border:1 ...

  10. python3+requests+unittest:接口自动化测试(一)

    转载请表明出处:https://www.cnblogs.com/shapeL/p/9179484.html 简单介绍框架的实现逻辑,参考代码的git地址: https://github.com/zha ...