!31 增加功能:增加手机短信验证码登录
This commit is contained in:
parent
c3bbe488ea
commit
7a75f9ec68
|
@ -2,6 +2,7 @@
|
||||||
using Bootstrap.DataAccess;
|
using Bootstrap.DataAccess;
|
||||||
using Longbow.GiteeAuth;
|
using Longbow.GiteeAuth;
|
||||||
using Longbow.GitHubAuth;
|
using Longbow.GitHubAuth;
|
||||||
|
using Longbow.Security.Cryptography;
|
||||||
using Longbow.Web;
|
using Longbow.Web;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
@ -64,6 +65,50 @@ namespace Bootstrap.Admin.Controllers
|
||||||
return User.Identity.IsAuthenticated ? (ActionResult)Redirect("~/Home/Index") : View("Login", new LoginModel());
|
return User.Identity.IsAuthenticated ? (ActionResult)Redirect("~/Home/Index") : View("Login", new LoginModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 短信验证登陆方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="onlineUserSvr"></param>
|
||||||
|
/// <param name="ipLocator"></param>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
|
/// <param name="phone"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost()]
|
||||||
|
public async Task<IActionResult> Mobile([FromServices]IOnlineUsers onlineUserSvr, [FromServices]IIPLocatorProvider ipLocator, [FromServices]IConfiguration configuration, [FromQuery]string phone, [FromQuery]string code)
|
||||||
|
{
|
||||||
|
var option = configuration.GetSection(nameof(SMSOptions)).Get<SMSOptions>();
|
||||||
|
if (UserHelper.AuthenticateMobile(phone, code, option.MD5Key, loginUser => CreateLoginUser(onlineUserSvr, ipLocator, HttpContext, loginUser)))
|
||||||
|
{
|
||||||
|
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
|
identity.AddClaim(new Claim(ClaimTypes.Name, phone));
|
||||||
|
identity.AddClaim(new Claim(ClaimTypes.Role, "Default"));
|
||||||
|
await HttpContext.SignInAsync(new ClaimsPrincipal(identity));
|
||||||
|
|
||||||
|
if (UserHelper.RetrieveUserByUserName(identity) == null)
|
||||||
|
{
|
||||||
|
var user = new User()
|
||||||
|
{
|
||||||
|
ApprovedBy = "Mobile",
|
||||||
|
ApprovedTime = DateTime.Now,
|
||||||
|
DisplayName = "手机用户",
|
||||||
|
UserName = phone,
|
||||||
|
Password = LgbCryptography.GenerateSalt(),
|
||||||
|
Icon = "default.jpg",
|
||||||
|
Description = "手机用户",
|
||||||
|
App = "2"
|
||||||
|
};
|
||||||
|
UserHelper.Save(user);
|
||||||
|
CacheCleanUtility.ClearCache(cacheKey: UserHelper.RetrieveUsersDataKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// redirect origin url
|
||||||
|
var originUrl = Request.Query[CookieAuthenticationDefaults.ReturnUrlParameter].FirstOrDefault() ?? "~/Home/Index";
|
||||||
|
return Redirect(originUrl);
|
||||||
|
}
|
||||||
|
return View("Login", new LoginModel() { AuthFailed = true });
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Login the specified userName, password and remember.
|
/// Login the specified userName, password and remember.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -5,15 +5,15 @@ using Longbow.Web;
|
||||||
using Longbow.Web.Mvc;
|
using Longbow.Web.Mvc;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Bootstrap.Admin.Controllers.Api
|
namespace Bootstrap.Admin.Controllers.Api
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// 登陆接口
|
||||||
/// </summary>
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
@ -28,7 +28,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
||||||
public QueryData<LoginUser> Get([FromQuery]QueryLoginOption value) => value.RetrieveData();
|
public QueryData<LoginUser> Get([FromQuery]QueryLoginOption value) => value.RetrieveData();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// JWT 登陆认证接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="onlineUserSvr"></param>
|
/// <param name="onlineUserSvr"></param>
|
||||||
/// <param name="ipLocator"></param>
|
/// <param name="ipLocator"></param>
|
||||||
|
@ -50,7 +50,25 @@ namespace Bootstrap.Admin.Controllers.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// 下发手机短信方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
|
/// <param name="factory"></param>
|
||||||
|
/// <param name="phone"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpPut]
|
||||||
|
public async Task<bool> Put([FromServices]IConfiguration configuration, [FromServices]IHttpClientFactory factory, [FromQuery]string phone)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(phone)) return false;
|
||||||
|
|
||||||
|
var option = configuration.GetSection(nameof(SMSOptions)).Get<SMSOptions>();
|
||||||
|
option.Phone = phone;
|
||||||
|
return await factory.CreateClient().SendCode(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 跨域握手协议
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
|
|
|
@ -47,30 +47,58 @@
|
||||||
<h2 class="form-signin-heading">@Model.Title</h2>
|
<h2 class="form-signin-heading">@Model.Title</h2>
|
||||||
<div class="login-wrap" data-auth="@Model.AuthFailed" data-toggle="LgbValidate" data-valid-button="button[type='submit']">
|
<div class="login-wrap" data-auth="@Model.AuthFailed" data-toggle="LgbValidate" data-valid-button="button[type='submit']">
|
||||||
<div class="alert alert-danger d-none" asp-condition="@Model.AuthFailed">用户名或密码错误!</div>
|
<div class="alert alert-danger d-none" asp-condition="@Model.AuthFailed">用户名或密码错误!</div>
|
||||||
<div class="form-group">
|
<div id="loginUser" class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<div class="input-group-text">
|
<div class="input-group-text">
|
||||||
<span class="fa fa-user"></span>
|
<span class="fa fa-user"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" name="userName" class="form-control" placeholder="用户名" maxlength="16" data-required-msg="请输入用户名" value="" autofocus data-valid="true" />
|
<input type="text" name="userName" class="form-control" data-toggle="tooltip" placeholder="用户名" maxlength="16" data-required-msg="请输入用户名" value="" autofocus data-valid="true" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div id="loginMobile" class="form-group d-none">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<div class="input-group-text">
|
||||||
|
<span class="fa fa-user"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" id="txtPhone" class="form-control digits" data-toggle="tooltip" placeholder="手机号码" minlength="11" maxlength="11" data-required-msg="请输入手机号码" value="" data-valid="true" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="loginPwd" class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<div class="input-group-text">
|
<div class="input-group-text">
|
||||||
<span class="fa fa-lock"></span>
|
<span class="fa fa-lock"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input type="password" name="password" class="form-control" value="" placeholder="密码" maxlength="16" data-required-msg="请输入密码" data-valid="true" />
|
<input type="password" name="password" class="form-control" value="" data-toggle="tooltip" placeholder="密码" maxlength="16" data-required-msg="请输入密码" data-valid="true" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group rememberPwd" onselectstart="return false">
|
<div id="loginSMS" class="form-group d-none">
|
||||||
<i class="fa fa-square-o"></i>
|
<div class="input-group">
|
||||||
<span>记住密码自动登录</span>
|
<div class="input-group-prepend">
|
||||||
<input id="remember" name="remember" type="hidden" value="false" />
|
<div class="input-group-text">
|
||||||
|
<span class="fa fa-lock"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" id="smscode" class="form-control digits" data-toggle="tooltip" disabled value="" placeholder="验证码" maxlength="4" data-required-msg="请输入验证码" data-valid="true" />
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button type="button" id="btnSendCode" class="btn btn-sms" data-toggle="tooltip" title="点击发送验证码">发送验证码</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div class="form-group rememberPwd" onselectstart="return false">
|
||||||
|
<i class="fa fa-square-o"></i>
|
||||||
|
<span>记住密码自动登录</span>
|
||||||
|
<input id="remember" name="remember" type="hidden" value="false" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a id="loginType" data-value="username" href="#" class="">短信验证登陆</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-lg btn-login btn-block" data-toggle="tooltip" title="不填写密码默认使用 Gitee 认证" type="submit">登 录</button>
|
<button class="btn btn-lg btn-login btn-block" data-toggle="tooltip" title="不填写密码默认使用 Gitee 认证" type="submit">登 录</button>
|
||||||
<div class="login-footer">
|
<div class="login-footer">
|
||||||
|
|
|
@ -82,6 +82,10 @@
|
||||||
"App": "0",
|
"App": "0",
|
||||||
"StarredUrl": "https://api.github.com/user/starred/ArgoZhang/BootstrapAdmin"
|
"StarredUrl": "https://api.github.com/user/starred/ArgoZhang/BootstrapAdmin"
|
||||||
},
|
},
|
||||||
|
"SMSOptions": {
|
||||||
|
"CompanyCode": "<CompanyCode>",
|
||||||
|
"MD5Key": "MD5Key"
|
||||||
|
},
|
||||||
"LongbowCache": {
|
"LongbowCache": {
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"CorsItems": [
|
"CorsItems": [
|
||||||
|
|
|
@ -86,6 +86,10 @@
|
||||||
"Roles": [ "Default" ],
|
"Roles": [ "Default" ],
|
||||||
"App": "2"
|
"App": "2"
|
||||||
},
|
},
|
||||||
|
"SMSOptions": {
|
||||||
|
"CompanyCode": "<CompanyCode>",
|
||||||
|
"MD5Key": "MD5Key"
|
||||||
|
},
|
||||||
"LongbowCache": {
|
"LongbowCache": {
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"CorsItems": [
|
"CorsItems": [
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
box-shadow: 0 4px #e56b60;
|
box-shadow: 0 4px #e56b60;
|
||||||
margin-bottom: 0.625rem;
|
margin-bottom: 0.625rem;
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
margin-top: -0.5rem;
|
margin-top: -0.25rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +57,8 @@
|
||||||
border-color: #1ca0e9;
|
border-color: #1ca0e9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
.form-control, .input-group-append .btn {
|
||||||
border-color: #1ca0e9;
|
border-color: #1ca0e9 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slidercaptcha {
|
.slidercaptcha {
|
||||||
|
@ -70,6 +70,7 @@
|
||||||
right: 0;
|
right: 0;
|
||||||
top: -270px;
|
top: -270px;
|
||||||
height: 226px;
|
height: 226px;
|
||||||
|
z-index: 1080
|
||||||
}
|
}
|
||||||
|
|
||||||
.slidercaptcha canvas:first-child {
|
.slidercaptcha canvas:first-child {
|
||||||
|
@ -144,3 +145,7 @@
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-wrap .btn-sms {
|
||||||
|
width: 140px;
|
||||||
|
}
|
||||||
|
|
|
@ -119,13 +119,97 @@
|
||||||
|
|
||||||
// use Gitee authentication when SystemDemoModel
|
// use Gitee authentication when SystemDemoModel
|
||||||
var $login = $('#login');
|
var $login = $('#login');
|
||||||
|
var $username = $('[name="userName"]');
|
||||||
|
var $password = $('[name="password"]');
|
||||||
|
var $loginUser = $('#loginUser');
|
||||||
|
var $loginMobile = $('#loginMobile');
|
||||||
|
var $loginPwd = $('#loginPwd');
|
||||||
|
var $loginSMS = $('#loginSMS');
|
||||||
if ($login.attr('data-demo') === 'True') {
|
if ($login.attr('data-demo') === 'True') {
|
||||||
$login.find('[data-valid="true"]').attr('data-valid', 'false');
|
|
||||||
$login.on('submit', function (e) {
|
$login.on('submit', function (e) {
|
||||||
if ($('[name="userName"]').val() === '' && $('[name="password"]').val() === '') {
|
var model = $loginType.attr('data-value');
|
||||||
location.href = "Gitee";
|
if (model === 'username') {
|
||||||
e.preventDefault();
|
$login.find('[data-valid="true"]').attr('data-valid', 'false');
|
||||||
|
if ($username.val() === '' && $password.val() === '') {
|
||||||
|
e.preventDefault();
|
||||||
|
location.href = "Gitee";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// sms
|
||||||
|
var url = $.format('Account/Mobile?phone={0}&code={1}', $('#txtPhone').val(), $('#smscode').val());
|
||||||
|
$login.attr('action', $.formatUrl(url));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// login type
|
||||||
|
var $loginType = $('#loginType').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $this = $(this);
|
||||||
|
$login.find('[data-toggle="tooltip"]').tooltip('hide');
|
||||||
|
var model = $this.attr('data-value');
|
||||||
|
if (model === 'username') {
|
||||||
|
$loginUser.addClass('d-none');
|
||||||
|
$loginPwd.addClass('d-none');
|
||||||
|
$loginSMS.removeClass('d-none');
|
||||||
|
$loginMobile.removeClass('d-none');
|
||||||
|
|
||||||
|
$this.attr('data-value', 'sms').text('用户名密码登陆');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// sms model
|
||||||
|
$loginUser.removeClass('d-none');
|
||||||
|
$loginPwd.removeClass('d-none');
|
||||||
|
$loginSMS.addClass('d-none');
|
||||||
|
$loginMobile.addClass('d-none');
|
||||||
|
|
||||||
|
$this.attr('data-value', 'username').text('短信验证登陆');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var timeHanlder = null;
|
||||||
|
$('#btnSendCode').on('click', function () {
|
||||||
|
// validate mobile phone
|
||||||
|
var $phone = $('#txtPhone');
|
||||||
|
var validator = $login.find('[data-toggle="LgbValidate"]').lgbValidator();
|
||||||
|
if (!validator.validElement($phone.get(0))) {
|
||||||
|
$phone.tooltip('show');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var phone = $phone.val();
|
||||||
|
var apiUrl = "api/Login?phone=" + phone;
|
||||||
|
var $this = $(this);
|
||||||
|
$.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').attr('data-original-title', "点击发送验证码");
|
||||||
|
}, 1500);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
// send success
|
||||||
|
$this.text('已发送').attr('disabled', true);
|
||||||
|
$('#smscode').removeAttr('disabled');
|
||||||
|
timeHanlder = setTimeout(function () {
|
||||||
|
clearTimeout(timeHanlder);
|
||||||
|
var count = 299;
|
||||||
|
timeHanlder = setInterval(function () {
|
||||||
|
if (count === 0) {
|
||||||
|
clearInterval(timeHanlder);
|
||||||
|
$this.text('发送验证码').removeAttr('disabled');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this.text(count-- + ' 秒后可重发');
|
||||||
|
}, 1000);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -0,0 +1,157 @@
|
||||||
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Bootstrap.DataAccess
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 手机号登陆帮助类
|
||||||
|
/// </summary>
|
||||||
|
public static class SMSHelper
|
||||||
|
{
|
||||||
|
private static ConcurrentDictionary<string, AutoExpireValidateCode> _pool = new ConcurrentDictionary<string, AutoExpireValidateCode>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下发验证码方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="option"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async System.Threading.Tasks.Task<bool> SendCode(this HttpClient client, SMSOptions option)
|
||||||
|
{
|
||||||
|
option.Timestamp = (DateTimeOffset.UtcNow.Ticks - 621355968000000000) / 10000000;
|
||||||
|
var requestParameters = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "CompanyCode", option.CompanyCode },
|
||||||
|
{ "Phone", option.Phone },
|
||||||
|
{ "TimeStamp", option.Timestamp.ToString() },
|
||||||
|
{ "Sign", option.Sign() }
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = QueryHelpers.AddQueryString("http://open.bluegoon.com/api/sms/sendcode", requestParameters);
|
||||||
|
var req = await client.GetAsync(url);
|
||||||
|
var result = JsonConvert.DeserializeObject<SMSResult>(await req.Content.ReadAsStringAsync());
|
||||||
|
var ret = false;
|
||||||
|
if (result.Code == "1")
|
||||||
|
{
|
||||||
|
_pool.AddOrUpdate(option.Phone, key => new AutoExpireValidateCode(option.Phone, result.Data, option.Expires), (key, v) => v.Reset(result.Data));
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证验证码方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="phone">手机号</param>
|
||||||
|
/// <param name="code">验证码</param>
|
||||||
|
/// <param name="secret">密钥</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool Validate(string phone, string code, string secret) => _pool.TryGetValue(phone, out var signKey) && Hash($"{code}{secret}") == signKey.Code;
|
||||||
|
|
||||||
|
private static string Sign(this SMSOptions option)
|
||||||
|
{
|
||||||
|
return Hash($"{option.CompanyCode}{option.Phone}{option.Timestamp}{option.MD5Key}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Hash(string data)
|
||||||
|
{
|
||||||
|
using (var md5 = MD5.Create())
|
||||||
|
{
|
||||||
|
var sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(data)));
|
||||||
|
sign = sign.Replace("-", "").ToLowerInvariant();
|
||||||
|
return sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SMSResult
|
||||||
|
{
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
public string Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AutoExpireValidateCode
|
||||||
|
{
|
||||||
|
public AutoExpireValidateCode(string phone, string code, TimeSpan expires)
|
||||||
|
{
|
||||||
|
Phone = phone;
|
||||||
|
Code = code;
|
||||||
|
Expires = expires;
|
||||||
|
RunAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Code { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Phone { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan Expires { get; set; }
|
||||||
|
|
||||||
|
private CancellationTokenSource _tokenSource;
|
||||||
|
|
||||||
|
private System.Threading.Tasks.Task RunAsync() => System.Threading.Tasks.Task.Run(() =>
|
||||||
|
{
|
||||||
|
_tokenSource = new CancellationTokenSource();
|
||||||
|
if (!_tokenSource.Token.WaitHandle.WaitOne(Expires)) _pool.TryRemove(Phone, out var _);
|
||||||
|
});
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
public AutoExpireValidateCode Reset(string code)
|
||||||
|
{
|
||||||
|
Code = code;
|
||||||
|
_tokenSource.Cancel();
|
||||||
|
RunAsync();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 短信网关配置类
|
||||||
|
/// </summary>
|
||||||
|
public class SMSOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 公司编码
|
||||||
|
/// </summary>
|
||||||
|
public string CompanyCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 下发手机号码
|
||||||
|
/// </summary>
|
||||||
|
public string Phone { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 签名密钥
|
||||||
|
/// </summary>
|
||||||
|
public string MD5Key { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 时间戳
|
||||||
|
/// </summary>
|
||||||
|
public long Timestamp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 验证码有效时长
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan Expires { get; set; } = TimeSpan.FromMinutes(5);
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,9 +58,9 @@ namespace Bootstrap.DataAccess
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userName"></param>
|
/// <param name="userName"></param>
|
||||||
/// <param name="password"></param>
|
/// <param name="password"></param>
|
||||||
/// <param name="config"></param>
|
/// <param name="configure"></param>
|
||||||
/// <returns>返回真表示认证通过</returns>
|
/// <returns>返回真表示认证通过</returns>
|
||||||
public static bool Authenticate(string userName, string password, Action<LoginUser> config)
|
public static bool Authenticate(string userName, string password, Action<LoginUser> configure)
|
||||||
{
|
{
|
||||||
if (!UserChecker(new User { UserName = userName, Password = password })) return false;
|
if (!UserChecker(new User { UserName = userName, Password = password })) return false;
|
||||||
var loginUser = new LoginUser
|
var loginUser = new LoginUser
|
||||||
|
@ -69,13 +69,36 @@ namespace Bootstrap.DataAccess
|
||||||
LoginTime = DateTime.Now,
|
LoginTime = DateTime.Now,
|
||||||
Result = "登录失败"
|
Result = "登录失败"
|
||||||
};
|
};
|
||||||
config(loginUser);
|
configure(loginUser);
|
||||||
var ret = string.IsNullOrEmpty(userName) ? false : DbContextManager.Create<User>().Authenticate(userName, password);
|
var ret = string.IsNullOrEmpty(userName) ? false : DbContextManager.Create<User>().Authenticate(userName, password);
|
||||||
if (ret) loginUser.Result = "登录成功";
|
if (ret) loginUser.Result = "登录成功";
|
||||||
LoginHelper.Log(loginUser);
|
LoginHelper.Log(loginUser);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 短信验证码认证方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="phone"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <param name="secret"></param>
|
||||||
|
/// <param name="configure"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool AuthenticateMobile(string phone, string code, string secret, Action<LoginUser> configure)
|
||||||
|
{
|
||||||
|
var loginUser = new LoginUser
|
||||||
|
{
|
||||||
|
UserName = phone,
|
||||||
|
LoginTime = DateTime.Now,
|
||||||
|
Result = "登录失败"
|
||||||
|
};
|
||||||
|
configure(loginUser);
|
||||||
|
var ret = string.IsNullOrEmpty(phone) ? false : SMSHelper.Validate(phone, code, secret);
|
||||||
|
if (ret) loginUser.Result = "登录成功";
|
||||||
|
LoginHelper.Log(loginUser);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询所有的新注册用户
|
/// 查询所有的新注册用户
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in New Issue