扫码登录
程序员文章站
2022-06-14 20:17:55
...
package cc.zenking.classcard.system.controller;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import cc.zenking.classcard.common.Const;
import cc.zenking.classcard.system.model.QrCodeResponse;
import cc.zenking.classcard.system.service.ScanService;
import cc.zenking.classcard.utils.RedisUtil;
import net.sf.json.JSONObject;
/**
* @ClassName: ScanController
* @Description: (扫码登录)
* @date 2019年7月11日 上午10:15:48
* @version V1.0
*
*/
@Controller
@RequestMapping("/zhbpappscan")
public class ScanController{
@Autowired
private RedisUtil rs;
@Autowired
private ScanService scanService;
/**
* 二维码 扫码登录 存储三分钟
*/
@Value("${zhbp.redis.auth.code.three}")
private long authCodeThree;
/**
* @param @return 设定文件
* @return ResponseEntity<Object> 返回类型
* @throws
* @Title: createQRCode
* @Description: (生成二维码并将uuid存储到redis中)
*/
@RequestMapping("/qrcode")
@ResponseBody
public JSONObject createQRCode() {
Map<String, Object>map = new HashMap<>();
map.put("status", 1);
map.put("reason", "成功");
map.put("data", 0);
String uuid = UUID.randomUUID().toString();
//组装二维码内容 zenking,1,uuid=xxxx
String text = Const.QRCODE_DOMAIN + "?type=" + Const.QRCODE_TYPE + "&uuid=" + uuid;
int width = 300;
int height = 300;
String format = "png";
Map<String, Object> uuidMap = new HashMap<>();
uuidMap.put("userId", "0");
//是否扫码 0未扫码,1扫码
uuidMap.put("isAppScan", "0");
try {
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// hints.put(EncodeHintType.MARGIN, 1);
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 容错率
BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, format, bao);
bao.toByteArray();
Base64 encoder = new Base64();
String img = encoder.encodeAsString(bao.toByteArray());
QrCodeResponse qrCodeResponse = new QrCodeResponse();
qrCodeResponse.setUuid(uuid);
qrCodeResponse.setImg(img);
rs.addMap(Const.QECODE + uuid, uuidMap);
rs.expire(Const.QECODE + uuid, authCodeThree);
map.put("data", qrCodeResponse);
} catch (WriterException e) {
map.put("status", -1000);
map.put("reason", "参数有误");
e.printStackTrace();
} catch (IOException e) {
map.put("status", -1000);
map.put("reason", "参数有误");
e.printStackTrace();
}
return JSONObject.fromObject(map);
}
/**
* @param @param uuid
* @param @return 设定文件
* @return ResponseEntity<Object> 返回类型
* @throws
* @Title: cleanRedisQrcode
* @Description: (扫码后未确认返回二维码登录时重置)
*/
@RequestMapping("/resetQrcode")
@ResponseBody
public JSONObject resetQrcode(String uuid) {
Map<String, Object>map = new HashMap<>();
map.put("status", 1);
map.put("reason", "成功");
map.put("data", 0);
try {
Object uuidExist = rs.getMapField(Const.QECODE + uuid, "userId", Object.class);
if (null == uuidExist) {
map.put("status", -6371);
map.put("reason", "redis中uuid不存在");
} else {
//扫描成功标识,用该标识展示“请在手机上确认登录”界面
rs.addMap(Const.QECODE + uuid, "isAppScan", "0");
}
} catch (Exception e) {
e.printStackTrace();
map.put("status", -6379);
map.put("reason", "uuid保存到redis中异常");
}
return JSONObject.fromObject(map);
}
/**
* @param @param uuid
* @param @param status 无值 或者 0的时候 返回扫过的状态 1的时候 不返回
* @param @return 设定文件
* @return ResponseEntity<Object> 返回类型
* @throws
* @Title: pool
* @Description: (检查二维码是否被扫描)
*/
@RequestMapping("/pool")
@ResponseBody
public JSONObject pool(String uuid, Integer status) {
Map<String, Object>map = new HashMap<>();
Map<String, Object>userInfoMap = new HashMap<>();
map.put("status", 1);
map.put("reason", "成功");
map.put("data", 0);
userInfoMap.put("userId", "");
userInfoMap.put("userName", "");
userInfoMap.put("portrait", "");
map.put("userInfo",userInfoMap);
//计时
int time = 0;
while (true) {
time++;
Map<String, Object> ad = rs.mget(Const.QECODE + uuid, Object.class);
if (ad == null || ad.size() == 0) {
//点击刷新 3代表超时,页面点击刷新
map.put("data", 3);
return JSONObject.fromObject(map);
}
if (ad != null && !("0".equals(ad.get("userId")))) {
//app扫过 并且登录 使用userId 生成token
int n = scanService.getUserInfo(Integer.parseInt(ad.get("userId").toString()));
if (n == 1) {
//登录后信息
map.put("userInfo", scanService.getLoginInfo(Integer.parseInt(ad.get("userId").toString())));
//2 代表成功登录状态
map.put("data", 2);
return JSONObject.fromObject(map);
} else {
//3代表 刷新
map.put("data", 3);
return JSONObject.fromObject(map);
}
}
if (ad != null && "1".equals(ad.get("isAppScan"))) {
//app扫过
if (status == null || status.intValue() == 0) {
//1 是 app扫过,弹出选择登录 还是 取消
map.put("data", 1);
return JSONObject.fromObject(map);
}
}
if (time >= 10) {
//保持10秒
map.put("data", 0);
return JSONObject.fromObject(map);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* @param @param uuid
* @param @param userId
* @param @return 设定文件
* @return ResponseEntity<Object> 返回类型
* @throws
* @Title: login
* @Description: (app按钮 : 允许登录)
*/
@RequestMapping("/appScanLogin")
@ResponseBody
public JSONObject appScanLogin(String uuid, String userId) {
Map<String, Object>map = new HashMap<>();
map.put("status", 1);
map.put("reason", "成功");
map.put("data", 0);
Map<String, Object> ad = rs.mget(Const.QECODE + uuid, Object.class);
if (null == ad||ad.isEmpty()) {
map.put("status", -1021);
map.put("reason", "请重新扫码");
} else {
//如果isAppScan状态是1才可以登录
if (ad.get("isAppScan") != null && "1".equals(ad.get("isAppScan"))) {
rs.addMap(Const.QECODE + uuid, "userId", userId);
}
}
return JSONObject.fromObject(map);
}
/**
* 功能描述:退出
*
* @param uuid
* @param userId
* @return: org.springframework.http.ResponseEntity<java.lang.Object>
*/
@RequestMapping(value = "/appScanCancel")
@ResponseBody
public JSONObject appScanCancel(String uuid, String userId) {
Map<String, Object>map = new HashMap<>();
map.put("status", 1);
map.put("reason", "成功");
try {
Map<String, Object> ad = rs.mget(Const.QECODE + uuid, Object.class);
if (null == ad || ad.isEmpty()) {
map.put("status", -1021);
map.put("reason", "请重新扫码");
}
//如果 isAppScan=1 则移除
if (ad.get("isAppScan") != null && "1".equals(ad.get("isAppScan"))) {
rs.del(Const.QECODE + uuid);
}
} catch (Exception e) {
e.printStackTrace();
map.put("status", -1021);
map.put("reason", "请重新扫码");
}
return JSONObject.fromObject(map);
}
/**
* @param uuid
* @param userId
* @return ResponseEntity<Object> 返回类型
* @Title: appScanEnd
* @Description: (app扫描二维码后)
*/
@RequestMapping("/appScanPrevious")
@ResponseBody
public JSONObject appScanPrevious(@RequestParam(value = "uuid", required = true) String uuid,
@RequestParam(value = "userId", required = true) String userId) {
Map<String, Object>map = new HashMap<>();
map.put("status", 1);
map.put("reason", "成功");
map.put("data", 0);
try {
Object uuidExist = rs.getMapField(Const.QECODE + uuid, "userId", Object.class);
if (null == uuidExist) {
map.put("status", -6371);
map.put("reason", "redis中uuid不存在");
} else {
//扫描成功标识,用该标识展示“请在手机上确认登录”界面
rs.addMap(Const.QECODE + uuid, "isAppScan", "1");
}
} catch (Exception e) {
e.printStackTrace();
map.put("status", -6379);
map.put("reason", "uuid保存到redis中异常");
}
return JSONObject.fromObject(map);
}
}
layui.extend({
common: '../lib/common'
}).define(['common', 'form', 'layer', 'element'], function (exports) {
var form = layui.form
, layer = layui.layer
, element = layui.element
, common = layui.common
, layerIndex = -1
, getQrCode = function (n) {//n=1是初始化
$.ajax({
type: "get",
url: common.prefix + "appscan/qrcode",
data: [],
cache: false,
dataType: 'json',
success: function (response) {
if (response) {
if (response.status == 1) {
$("#qrcode").attr("src", "data:image/png;base64," + response.data.img);
if (n == 1) {
keepPool(response.data.uuid, 0);
$("#redisUUID").val(response.data.uuid);
}
}
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (textStatus == null || textStatus == "") {
} else {
}
}
});
}
, keepPool = function (uuid, status) {//status=1 已经扫描 等待登录
if (!status) {
status = 0;
}
$.ajax(
{
type: "get",
url: common.prefix + "appscan/pool",
data: {uuid: uuid, status: status},
cache: false,
dataType: 'json',
success: function (data) {
if (data && data.status == '1') {
if (data.data == '1') {
//扫码成功
$('.scan-box').addClass('layui-hide');
$('.scanned-box').removeClass('layui-hide');
$('.lapse-box').addClass('layui-hide');
keepPool(uuid, 1);
} else if (data.data == '2') {
//如果有返回地址 则重定向回
var redirectUri = "";
redirectUri = common.getRequest().redirectUri;
if (redirectUri) {
var token = "?token=" + common.getCookie("token");
if (!token) {
token = "";
}
top.location.replace(redirectUri + token);
}
else {
window.location.replace(common.prefix + "view/index.html");
}
} else if (data.data == '3') {
//点击刷新
$('.scan-box').addClass('layui-hide');
$('.scanned-box').addClass('layui-hide');
$('.lapse-box').removeClass('layui-hide');
} else {
keepPool(uuid, 0);
}
}
else {
keepPool(uuid, 0);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (textStatus == "timeout") {
keepPool(uuid, 0);
} else {
keepPool(uuid, 0);
}
}
}
);
}
// 检测是否需要强制修改密码
, checkUpdatePwd = function () {
$.ajax({
type: "post",
url: common.prefix + "user/constraintUpdatePwd",
async: false,
dataType: 'json',
success: function (result) {
if (result.status != 1) {
form.val("formPwd",{
'pwd':'',
'pwdSure':''
});
layer.open({
type: 1,
title: false,
closeBtn: 0,
content: $('#updatePwd'),
area: ['680px','440px'],
resize: false,
scrollbar: false,
success: function(layero, index){
layerIndex = index;
$('#updatePwd').removeClass('layui-hide');
},
end: function(){
$('#updatePwd').addClass('layui-hide');
form.val("formPwd",{
'pwd':'',
'pwdSure':''
});
}
});
} else {
logIn();
}
}
});
}
// 登入系统
, logIn = function () {
//如果有返回地址 则重定向回
var redirectUri = "";
redirectUri = common.getRequest().redirectUri;
if (redirectUri) {
//带上token
var token = "?token=" + common.getCookie("token");
if (!token) {
token = "";
}
top.location.replace(redirectUri + token);
}
else {
window.location.replace(common.prefix + "view/index.html");
}
}
, initListeners = function () {
//二维码
getQrCode(1);
// 扫码
$("body").on("click", "[data-scan]", function () {
var type = $(this).attr("data-scan");
var $parent = $(this).parents(".scan");
$parent.addClass("layui-hide");
$(".scan-box").removeClass("layui-hide");
if (type == 'back') {
// '返回'
//调用接口 重置 redis中的uuid ajax成功后 调用 getQrCode(1);
var redisUUID = $("#redisUUID").val();
$.ajax({
type: "get",
url: common.prefix + "appscan/resetQrcode",
data: {uuid: redisUUID},
cache: false,
dataType: 'json',
success: function (response) {
if (response) {
if (response.status == 1) {
//window.location.reload();
//getQrCode(0);
} else {
lay.msg(response.reason);
}
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (textStatus == null || textStatus == "") {
} else {
}
}
});
} else if (type == 'refresh') {
// '刷新'
getQrCode(1);
}
});
// 帐号登录
$("body").on("click", "[data-logintype]", function () {
var type = $(this).attr("data-logintype");
var $tabTitle = $("[data-account]");
var newTab = '', newPlaceholder = '', newType = '', newBtntxt = '';
if (type == 'student') {
// 切换为学生
newTab = "学生登录";
newPlaceholder = '帐号';
newType = 'zksc';
newBtntxt = '<i class="layui-icon layui-icon-return"></i>返回';
$("[data-zksc]").addClass("layui-hide");
$("[data-student]").removeClass("layui-hide");
} else if (type == 'zksc') {
// 帐号
newTab = "帐号登录";
newPlaceholder = '手机号';
newType = 'student';
newBtntxt = '学生登录';
$("[data-student]").addClass("layui-hide");
$("[data-zksc]").removeClass("layui-hide");
}
$tabTitle.text(newTab);
$(this).attr("data-logintype", newType).html(newBtntxt);
$("[name='username']").attr("placeholder", newPlaceholder);
$('[name="username"]').val("");
$('[name="password"]').val("");
$('[name="authcode"]').val("");
});
//监听提交
form.on('submit(loginform)', function (data) {
type = gettype();
$.ajax({
type: "post",
url: common.prefix + "user/login",
data: {
type: type,
username: $.trim($("[name='username']").val()),
password: $.trim($("[name='password']").val()),
code: $.trim($("[name='authcode']").val()),
loginType: 1
},
async: false,
dataType: 'json',
success: function (result) {
if (result.status != 1) {
if(result.data){
// 被锁定
if(result.data.loginErrorStatus==4){
layer.open({'title':'您的帐号已被禁用,暂时无法登录', 'content':'<div><i class="icon-danger"></i></div>'+result.reason, closeBtn:0, skin: 'login-layer'});
} else {
layer.open({'title':'温馨提示', 'content':result.reason, closeBtn:0, skin: 'login-layer',
yes: function(index, layero){
if(result.data.loginErrorStatus==2){
// 账号或密码错误时,刷新验证码
$('#imgCode').attr('src', 'user/validateCode?'+Math.random());
}
layer.close(index);
}
});
}
} else {
layer.open({'title':'温馨提示', 'content':result.reason, closeBtn:0, skin: 'login-layer'});
}
return;
}
//检测是否需要强制修改密码
checkUpdatePwd();
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (textStatus == null || textStatus == "") {
layer.msg(errorThrown);
} else {
layer.msg(textStatus);
}
}
});
return false;
});
// 提交,强制修改密码
form.on('submit(updatePwd)', function (data) {
var phone=$(".account input[name='username']").val();
var field=data.field;
$.ajax({
type:'POST',
url:common.prefix+'forgetPwd/setNewPwd',
data:{phoneNo:phone, pwd:field.pwd, pwdSure:field.pwdSure},
cache:false,
dataType:'json',
success:function(result) {
layer.close(layerIndex);
layerIndex = -1; // 重置
if(result.status==1){
layer.open({'title':'温馨提示', 'content':'修改成功,请重新登录!'});
$(".account input[name='password']").val("");
} else {
layer.msg(result.reason,{title:false,icon:5,closeBtn:0,shade:0,time:3000});
}
}
});
return false;
});
form.verify({
password: function(value){
if(value.trim().length<8){
return '密码不能少于8位';
} else if(value.trim().length>24){
return '密码不能超过24位';
} else if( !(/^(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,24}$/.test(value)) && !(/^(?=.*[a-z])(?=.*\d)[A-Za-z\d]{8,24}$/.test(value)) ){
return '密码要字母加数字进行组合';
}
}
,equalPwd: function(value){
var pwd1=$("[name='pwd']").val().trim(),
pwd2=$("[name='pwdSure']").val().trim();
if(pwd1!=pwd2){
return '两次密码不一致';
}
}
});
// 禁止输入空格
$("form").on("keypress", "input[name='username'],input[name='password']", function (event) {
var evt = arguments.callee.caller.arguments[0];
var key = evt.charCode;
if (key == 32) {
event.preventDefault();
}
});
// 回车登录
$("body").bind("keyup",function(event){
var showFlag = $(".account").hasClass("layui-show");
if(!showFlag){
return;
}
var evt=arguments.callee.caller.arguments[0];
var key = evt.keyCode;
if(key == 13){
var $layer = $("body>.layui-layer");
if($layer.length==0){
// 登录
$("[lay-filter='loginform']").click();
}
}
});
// 发送验证码
$("[name='btnCode']").bind("click", function () {
if ($("body").find(".error").length > 0) {
return false;
}
var flag = validRequired('username');
if (!flag) {
layer.msg("请填写手机号!");
return false;
}
flag = validRequired('password');
if (!flag) {
layer.msg("请填写密码!");
return false;
}
sendcode(common.prefix, $(this));
});
// 用户协议
form.on('checkbox(agreement)', function(data){
var $parent = $(data.elem).parents(".form-btn");
$btn = $parent.find('[lay-filter="loginform"]');
if(data.elem.checked){
// 勾选
$btn.removeClass("layui-btn-disabled").removeAttr("disabled");
} else {
$btn.addClass("layui-btn-disabled").attr("disabled",true);
}
});
// 强制重置密码,监听密码输入框,改变‘确定’按钮状态
$("#updatePwd").on("input porpertychange","input[required]",function(){
var pwd1 = $("#updatePwd [name='pwd']").val().trim();
var pwd2 = $("#updatePwd [name='pwdSure']").val().trim();
if(pwd1!=""&&pwd2!=""){
$("#updatePwd .layui-btn").removeClass("layui-btn-disabled").removeAttr("disabled");
} else {
$("#updatePwd .layui-btn").addClass("layui-btn-disabled").attr("disabled","disabled");
}
});
};
var type = 0;
var sTime; //发送间隔时间
initListeners();
exports('login', {});
});
/**
* 获取登录名称类型
*/
function gettype() {
if ($("body").find(".error").length > 0) {
return false;
}
var flag = validRequired('username');
if (!flag) {
return false;
}
flag = validRequired('password');
if (!flag) {
return false;
}
if (/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-][email protected][a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test($.trim($("[name='username']").val()))) {
type = 2;
} else if (/^1[0-9]{10}$/.test($.trim($("[name='username']").val()))) {
type = 1;
} else {
type = 0;
}
return type;
}
/**
* 发送验证码
* @param wrap
*/
function sendcode(commonUrl, wrap) {
gettype();
wrap.attr("disabled","disabled").addClass("layui-btn-disabled");
$.ajax({
type: "post",
url: commonUrl + "user/sendLoginRandomNo",
data: {
type: type,
phoneNo: $.trim($("[name='username']").val()),
password: $.trim($("[name='password']").val()),
loginType: 0
},
async: false,
dataType: 'json',
success: function (data) {
if (data.status != 1) {
layer.msg(data.reason);
wrap.removeAttr("disabled").removeClass("layui-btn-disabled");
} else {
layer.msg("验证码发送成功,请注意查收");
if (wrap) {
sTime = 60;
resendtime(wrap);
}
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (textStatus == null || textStatus == "") {
layer.msg(errorThrown);
} else {
layer.msg(textStatus);
}
}
});
}
//设置定时,1分钟后才能重新发送
function resendtime(wrap) {
if (sTime != 0) {
wrap.val("获取验证码("+sTime+")");
sTime--;
setTimeout(function () {
resendtime(wrap)
}, 1000)
} else {
wrap.removeAttr("disabled").val("获取验证码").removeClass("layui-btn-disabled");
}
}
function validRequired(name) {
var flag = true;
var that = $("[name='" + name + "']");
var value = that.val();
if (value == "") {
flag = false;
}
return flag;
}
function replaceNull(obj) {
var exp = obj;
if (typeof(exp) == "undefined" || exp == null) {
return "";
}
return obj;
}