增加功能:登录页面智能判断是否开启行为式验证码 closed #ITNDE
#Issue https://gitee.com/LongbowEnterprise/dashboard/issues?id=ITNDE #Comment comment 30秒内登录超过三次后开始行为验证码
This commit is contained in:
parent
f9f3522d7c
commit
260ff5691d
|
@ -1,8 +1,12 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Bootstrap.Admin.Controllers.Api
|
namespace Bootstrap.Admin.Controllers.Api
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -34,5 +38,102 @@ namespace Bootstrap.Admin.Controllers.Api
|
||||||
var user = onlineUSers.OnlineUsers.FirstOrDefault(u => u.ConnectionId == id);
|
var user = onlineUSers.OnlineUsers.FirstOrDefault(u => u.ConnectionId == id);
|
||||||
return user?.RequestUrls ?? new KeyValuePair<DateTime, string>[0];
|
return user?.RequestUrls ?? new KeyValuePair<DateTime, string>[0];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// 登录页面检查调用
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>返回真时 启用行为验证码</returns>
|
||||||
|
[HttpPut]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public bool Put()
|
||||||
|
{
|
||||||
|
var ip = (Request.HttpContext.Connection.RemoteIpAddress ?? IPAddress.IPv6Loopback).ToString();
|
||||||
|
if (_loginUsers.TryGetValue(ip, out var user))
|
||||||
|
{
|
||||||
|
user.Reset();
|
||||||
|
user.User.Count++;
|
||||||
|
return user.User.Count > 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var loginUser = new LoginUser() { Ip = ip };
|
||||||
|
_loginUsers.TryAdd(ip, new LoginUserCache(loginUser, () => _loginUsers.TryRemove(ip, out _)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ConcurrentDictionary<string, LoginUserCache> _loginUsers = new ConcurrentDictionary<string, LoginUserCache>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
private class LoginUser
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Ip { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public int Count { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
private class LoginUserCache : IDisposable
|
||||||
|
{
|
||||||
|
private Timer dispatcher;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
/// <param name="action"></param>
|
||||||
|
public LoginUserCache(LoginUser user, Action action)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
dispatcher = new Timer(_ => action(), null, TimeSpan.FromSeconds(30), Timeout.InfiniteTimeSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public LoginUser User { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
if (dispatcher != null) dispatcher.Change(TimeSpan.FromSeconds(30), Timeout.InfiniteTimeSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Impletement IDispose
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing"></param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (dispatcher != null)
|
||||||
|
{
|
||||||
|
dispatcher.Dispose();
|
||||||
|
dispatcher = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,19 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$.extend({
|
||||||
|
captchaCheck: function (success) {
|
||||||
|
$.bc({
|
||||||
|
url: "api/OnlineUsers",
|
||||||
|
method: "put",
|
||||||
|
callback: function (result) {
|
||||||
|
if (result) $captcha.addClass('d-block');
|
||||||
|
else success();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('#btnSubmit').on('click', function () {
|
$('#btnSubmit').on('click', function () {
|
||||||
$.bc({
|
$.bc({
|
||||||
url: "api/Register",
|
url: "api/Register",
|
||||||
|
@ -53,21 +66,22 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
var $captcha = $('.slidercaptcha');
|
var $captcha = $('.slidercaptcha');
|
||||||
$('.slidercaptcha .close').on('click', function() {
|
$('.slidercaptcha .close').on('click', function () {
|
||||||
$captcha.removeClass('d-block');
|
$captcha.removeClass('d-block');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('button[type="submit"]').on('click', function(e){
|
$('button[type="submit"]').on('click', function (e) {
|
||||||
//if ($.browser.versions.mobile) return true;
|
$.captchaCheck(function () {
|
||||||
$captcha.addClass('d-block');
|
$('form').submit();
|
||||||
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#captcha').sliderCaptcha({
|
$('#captcha').sliderCaptcha({
|
||||||
width: $(window).width() < 768 ? 216 : 280,
|
width: $(window).width() < 768 ? 216 : 280,
|
||||||
height: $(window).width() < 768 ? 110 : 150,
|
height: $(window).width() < 768 ? 110 : 150,
|
||||||
setSrc: function() {
|
setSrc: function () {
|
||||||
return 'http://pocoafrro.bkt.clouddn.com/Pic' + Math.round(Math.random() * 136) + '.jpg'
|
return 'http://pocoafrro.bkt.clouddn.com/Pic' + Math.round(Math.random() * 136) + '.jpg';
|
||||||
},
|
},
|
||||||
onSuccess: function () {
|
onSuccess: function () {
|
||||||
$('form').submit();
|
$('form').submit();
|
||||||
|
|
Loading…
Reference in New Issue