feat: 短信验证码锁屏功能
This commit is contained in:
parent
80850165a6
commit
14ea70fae5
|
@ -24,6 +24,7 @@ namespace Bootstrap.Admin.Controllers
|
|||
[AutoValidateAntiforgeryToken]
|
||||
public class AccountController : Controller
|
||||
{
|
||||
private const string MobileSchema = "Mobile";
|
||||
/// <summary>
|
||||
/// 系统锁屏界面
|
||||
/// </summary>
|
||||
|
@ -33,10 +34,12 @@ namespace Bootstrap.Admin.Controllers
|
|||
{
|
||||
if (!User.Identity.IsAuthenticated) return Login();
|
||||
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
var authenticationType = User.Identity.AuthenticationType;
|
||||
await HttpContext.SignOutAsync();
|
||||
var urlReferrer = Request.Headers["Referer"].FirstOrDefault();
|
||||
return View(new LockModel(this)
|
||||
{
|
||||
AuthenticationType = authenticationType,
|
||||
ReturnUrl = WebUtility.UrlEncode(string.IsNullOrEmpty(urlReferrer) ? CookieAuthenticationDefaults.LoginPath.Value : urlReferrer)
|
||||
});
|
||||
}
|
||||
|
@ -44,15 +47,20 @@ namespace Bootstrap.Admin.Controllers
|
|||
/// <summary>
|
||||
/// 系统锁屏界面
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <param name="authType"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[IgnoreAntiforgeryToken]
|
||||
public Task<IActionResult> Lock(string userName, string password)
|
||||
public Task<IActionResult> Lock([FromServices]IConfiguration configuration, string userName, string password, string authType)
|
||||
{
|
||||
// 根据不同的登陆方式
|
||||
return Login(userName, password, string.Empty);
|
||||
Task<IActionResult> ret;
|
||||
if (authType == MobileSchema) ret = Mobile(configuration, userName, password);
|
||||
else ret = Login(userName, password, string.Empty);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -73,7 +81,6 @@ namespace Bootstrap.Admin.Controllers
|
|||
/// <summary>
|
||||
/// 短信验证登陆方法
|
||||
/// </summary>
|
||||
/// <param name="ipLocator"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="phone"></param>
|
||||
/// <param name="code"></param>
|
||||
|
@ -107,7 +114,7 @@ namespace Bootstrap.Admin.Controllers
|
|||
RoleHelper.SaveByUserId(user.Id, roles);
|
||||
}
|
||||
}
|
||||
return auth ? await SignInAsync(phone, true) : View("Login", new LoginModel() { AuthFailed = true });
|
||||
return auth ? await SignInAsync(phone, true, MobileSchema) : View("Login", new LoginModel() { AuthFailed = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -125,9 +132,9 @@ namespace Bootstrap.Admin.Controllers
|
|||
return auth ? await SignInAsync(userName, remember == "true") : View("Login", new LoginModel() { AuthFailed = true });
|
||||
}
|
||||
|
||||
private async Task<IActionResult> SignInAsync(string userName, bool persistent)
|
||||
private async Task<IActionResult> SignInAsync(string userName, bool persistent, string authenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
{
|
||||
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
var identity = new ClaimsIdentity(authenticationScheme);
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, userName));
|
||||
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties { ExpiresUtc = DateTimeOffset.Now.AddDays(DictHelper.RetrieveCookieExpiresPeriod()), IsPersistent = persistent });
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bootstrap.Admin.Models
|
||||
{
|
||||
|
@ -20,5 +20,10 @@ namespace Bootstrap.Admin.Models
|
|||
/// 获得/设置 返回路径
|
||||
/// </summary>
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 认证方式 Cookie Mobile Gitee GitHub
|
||||
/// </summary>
|
||||
public string AuthenticationType { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
<img alt="lock avatar" src="@Url.Content(Model.Icon)" />
|
||||
<h1>@Model.DisplayName</h1>
|
||||
<span class="locked">系统已锁定</span>
|
||||
<form role="form" class="form-inline justify-content-center" method="post" autocomplete="off" action="~/Account/Lock?ReturnUrl=@Model.ReturnUrl">
|
||||
<input type="hidden" name="username" value="@Model.UserName" />
|
||||
<form role="form" class="form-inline justify-content-center @Model.AuthenticationType" method="post" autocomplete="off" action="?ReturnUrl=@Model.ReturnUrl">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input type="password" name="password" class="form-control" value="" autocomplete="off" placeholder="密码" />
|
||||
|
@ -42,6 +41,21 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="username" value="@Model.UserName" />
|
||||
<input type="hidden" name="authType" value="@Model.AuthenticationType" />
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">
|
||||
<span class="fa fa-lock"></span>
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" id="smscode" class="form-control" data-toggle="tooltip" disabled value="" placeholder="验证码" maxlength="4" title="请输入验证码" />
|
||||
<div class="input-group-append">
|
||||
<button type="button" id="btnSendCode" class="btn btn-lock btn-sms" data-method="send" data-toggle="tooltip" title="点击发送验证码">发送验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -84,30 +84,51 @@ body {
|
|||
border-color: #3c763d;
|
||||
}
|
||||
|
||||
div.input-group span {
|
||||
top: 0;
|
||||
background: #02b5c2;
|
||||
border-color: #2e6da4;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.form-inline .input-group input:focus {
|
||||
z-index: auto;
|
||||
}
|
||||
|
||||
div.input-group input, div.input-group input:hover, .btn-lock {
|
||||
.lock-box .form-inline .form-group {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lock-box .form-inline.Cookies .form-group:first-child {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.lock-box .form-inline.Mobile .form-group:last-child {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
div.input-group span {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
div.input-group input, div.input-group input:hover, .btn-lock, div.input-group .input-group-text {
|
||||
border-color: #1d9238;
|
||||
}
|
||||
|
||||
div.input-group input:focus {
|
||||
box-shadow: none;
|
||||
div.input-group input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
div.input-group input, div.input-group input:hover, div.input-group input:focus {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
div.input-group input.error {
|
||||
background-color: #dcc4c4;
|
||||
border-color: #e21717;
|
||||
}
|
||||
|
||||
div.input-group .input-group-text {
|
||||
background-color: #02b5c2;
|
||||
}
|
||||
|
||||
div.input-group input, div.input-group input:hover, div.input-group input:focus {
|
||||
border-right: none;
|
||||
.btn-sms {
|
||||
width: 122px;
|
||||
}
|
||||
|
||||
div.input-group input.error {
|
||||
background-color: #dcc4c4;
|
||||
border-color: #e21717;
|
||||
}
|
||||
.form-group:last-child input {
|
||||
width: 80px;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
$(function () {
|
||||
$(function () {
|
||||
$('#time').text((new Date()).format('HH:mm:ss'));
|
||||
|
||||
setInterval(function () {
|
||||
|
@ -6,4 +6,60 @@ $(function () {
|
|||
}, 500);
|
||||
|
||||
$(".lock-wrapper").autoCenter();
|
||||
|
||||
var timeHanlder = null;
|
||||
$('#btnSendCode').on('click', function () {
|
||||
var $this = $(this);
|
||||
var method = $this.attr('data-method');
|
||||
var phone = $('input[name="username"]').val();
|
||||
var $password = $('input[name="password"]');
|
||||
var $code = $('#smscode');
|
||||
var code = $code.val();
|
||||
if (method === 'submit') {
|
||||
if ($code.val() === '') {
|
||||
$code.tooltip('show');
|
||||
var handler = setTimeout(function () {
|
||||
clearTimeout(handler);
|
||||
$code.tooltip('hide');
|
||||
}, 1000);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 提交
|
||||
$password.val(code);
|
||||
$('form').submit();
|
||||
return true;
|
||||
}
|
||||
// validate mobile phone
|
||||
var apiUrl = "api/Login?phone=" + phone;
|
||||
$.bc({
|
||||
url: apiUrl,
|
||||
method: 'PUT',
|
||||
callback: function (result) {
|
||||
$this.attr('data-original-title', result ? "发送成功" : "发送失败").tooltip('show');
|
||||
var handler = setTimeout(function () {
|
||||
clearTimeout(handler);
|
||||
$this.tooltip('hide').tooltip('disable');
|
||||
}, 1000);
|
||||
|
||||
if (result) {
|
||||
// send success
|
||||
$('#smscode').removeAttr('disabled');
|
||||
$this.text('已发送').attr('data-method', 'submit');
|
||||
timeHanlder = setTimeout(function () {
|
||||
clearTimeout(timeHanlder);
|
||||
var count = 299;
|
||||
timeHanlder = setInterval(function () {
|
||||
if (count === 0) {
|
||||
clearInterval(timeHanlder);
|
||||
$this.text('发送验证码').attr('data-method', 'send').attr('data-original-title', "点击发送验证码").tooltip('enable');
|
||||
return;
|
||||
}
|
||||
$this.text('登录 (' + count-- + 's)');
|
||||
}, 1000);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -190,7 +190,7 @@
|
|||
var handler = setTimeout(function () {
|
||||
clearTimeout(handler);
|
||||
$this.tooltip('hide').attr('data-original-title', "点击发送验证码");
|
||||
}, 1500);
|
||||
}, 1000);
|
||||
|
||||
if (result) {
|
||||
// send success
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Bootstrap.DataAccess
|
|||
City = ipLocator.Locate(ip),
|
||||
Browser = $"{agent.Browser?.Name} {agent.Browser?.Version}",
|
||||
OS = $"{agent.OS?.Name} {agent.OS?.Version}",
|
||||
Result = auth ? "登陆成功" : "登录失败"
|
||||
Result = auth ? "登录成功" : "登录失败"
|
||||
};
|
||||
return DbContextManager.Create<LoginUser>().Log(loginUser);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue