利用MYSQL的函数实现用户登录功能,进出都是JSON(第二版)

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的函数实现用户登录功能,进出都是JSON(第二版)的更多相关文章

  1. 利用MYSQL的函数实现用户登录功能,进出都是JSON(第一版)

    以HMAC密钥形式发放密钥令牌 功能如下 1:记录用户的登录的IP地址.时间 2:实现密码错误次数超限后锁定,并提示何时解锁 CREATE DEFINER=`root`@`%` FUNCTION `u ...

  2. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  3. Struts2整合Hibernate3实现用户登录功能

    所用技术:struts2 ,hibernate,jsp,mysql 本DEMO仅仅实现用户登录功能,采用MVC思想,自己也觉得相对是比较简单,比较容易理解数据流向的一个例子,通过整合这个过程,能够清晰 ...

  4. JavaWeb学习记录(六)——用户登录功能

    使用JDBC.spring框架.servlet实现一个简单的用户登录功能. 一.mySql数据库 SET FOREIGN_KEY_CHECKS=0; -- ---------------------- ...

  5. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(五)——实现注册功能

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  6. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  7. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(三)——使用Flask-Login库实现登录功能

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  8. VuePress 中增加用户登录功能

    在 VuePress 中增加用户登录 VuePress 是 Vuejs 官方提供的一个快速建设文档站点的工具,在简单配置好功能后,需要做的事情就剩下写好一个个 Markdown 文档. 因为 VueP ...

  9. 实现Web上的用户登录功能

    关于如何实现web上的自动登录功能 文章来源http://coolshell.cn/articles/5353.html Web上的用户登录功能应该是最基本的功能了,可是在我看过一些站点的用户登录功能 ...

随机推荐

  1. Spring 注入集合

    Spring 中,注入集合类型的数值方式 <bean id="javaCollection" class="com.qie_zi.JavaCollection&qu ...

  2. 剑指Offer 60. 把二叉树打印成多行 (二叉树)

    题目描述 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 题目地址 https://www.nowcoder.com/practice/445c44d982d04483b04a54f ...

  3. 定时清理elasticsearch

    索引这种格式 以下脚本加入crontab #每天清理es数据 0 1 * * * /data/sh/rm_esindex.sh >> /data/logs/crontab/rm_esind ...

  4. Android Studio 入口程序的设置方法

    在src -> main中 ,打开 AndroidManifest.xml 这个文件 下面这里有两个窗口,如果要想把哪个窗口设置成入口窗体,只要把下面红色的放在这个节点中就可以了 <act ...

  5. .NET Framework 4.0/4.5离线版下载

    /******************************************************************************* * .NET Framework 4. ...

  6. ubuntu18.04LTS配置apache虚拟目录(基于端口)

    假设在用户目录下要新建两个虚拟目录web1,web2,分别对应端口8081,8082 $ cd ~ #切换到用户目录 $ mkdir www #新建www文件夹,以后新建的虚拟目录都放在该文件夹下 $ ...

  7. shell脚本-2

    http://www.runoob.com/linux/linux-shell-variable.html 字符串可以用单引号,也可以用双引号,也可以不用引号.单双引号的区别跟PHP类似. 单引号字符 ...

  8. C# 中String.Join()方法

    今天在工作中看到了组里一个大佬写的代码,感触颇多,同样实现一个需求,我写循环费了老大劲,代码又臭又长,大佬的代码简洁明了,三行搞定...不得不说,今天赚大了 简单总结一下今天赚到的知识 string里 ...

  9. 8th week blog

    1.indexof() indexOf()的用法:返回字符中indexof(string)中字串string在父串中首次出现的位置,从0开始,没有返回-1:方便判断和截取字符串!indexOf()定义 ...

  10. 对spring框架的理解

    spring框架的两大核心理念就是IOC和AOP,在面试的时候经常会被问到你对spring的理解.下面大致的说一下我对spring的理解. 一.IoC 1.1.什么是IoC 众所周知,IoC就是控制反 ...