diff --git a/Bootstrap.Admin/Controllers/Api/OnlineUsersController.cs b/Bootstrap.Admin/Controllers/Api/OnlineUsersController.cs index 6b3b86a7..edd4a65a 100644 --- a/Bootstrap.Admin/Controllers/Api/OnlineUsersController.cs +++ b/Bootstrap.Admin/Controllers/Api/OnlineUsersController.cs @@ -1,8 +1,12 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; - +using System.Net; +using System.Threading; + namespace Bootstrap.Admin.Controllers.Api { /// @@ -34,5 +38,102 @@ namespace Bootstrap.Admin.Controllers.Api var user = onlineUSers.OnlineUsers.FirstOrDefault(u => u.ConnectionId == id); return user?.RequestUrls ?? new KeyValuePair[0]; } - } + + /// + /// 登录页面检查调用 + /// + /// 返回真时 启用行为验证码 + [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 _loginUsers = new ConcurrentDictionary(); + + /// + /// + /// + private class LoginUser + { + /// + /// + /// + public string Ip { get; set; } + + /// + /// + /// + public int Count { get; set; } + } + + /// + /// + /// + private class LoginUserCache : IDisposable + { + private Timer dispatcher; + + /// + /// + /// + /// + /// + public LoginUserCache(LoginUser user, Action action) + { + User = user; + dispatcher = new Timer(_ => action(), null, TimeSpan.FromSeconds(30), Timeout.InfiniteTimeSpan); + } + + /// + /// + /// + public LoginUser User { get; set; } + + /// + /// + /// + public void Reset() + { + if (dispatcher != null) dispatcher.Change(TimeSpan.FromSeconds(30), Timeout.InfiniteTimeSpan); + } + + #region Impletement IDispose + /// + /// + /// + /// + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (dispatcher != null) + { + dispatcher.Dispose(); + dispatcher = null; + } + } + } + /// + /// + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } + } } diff --git a/Bootstrap.Admin/wwwroot/js/login.js b/Bootstrap.Admin/wwwroot/js/login.js index d571303c..aae019de 100644 --- a/Bootstrap.Admin/wwwroot/js/login.js +++ b/Bootstrap.Admin/wwwroot/js/login.js @@ -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 () { $.bc({ url: "api/Register", @@ -53,21 +66,22 @@ }); var $captcha = $('.slidercaptcha'); - $('.slidercaptcha .close').on('click', function() { + $('.slidercaptcha .close').on('click', function () { $captcha.removeClass('d-block'); }); - $('button[type="submit"]').on('click', function(e){ - //if ($.browser.versions.mobile) return true; - $captcha.addClass('d-block'); + $('button[type="submit"]').on('click', function (e) { + $.captchaCheck(function () { + $('form').submit(); + }); return false; }); $('#captcha').sliderCaptcha({ width: $(window).width() < 768 ? 216 : 280, height: $(window).width() < 768 ? 110 : 150, - setSrc: function() { - return 'http://pocoafrro.bkt.clouddn.com/Pic' + Math.round(Math.random() * 136) + '.jpg' + setSrc: function () { + return 'http://pocoafrro.bkt.clouddn.com/Pic' + Math.round(Math.random() * 136) + '.jpg'; }, onSuccess: function () { $('form').submit();