diff --git a/src/admin/Bootstrap.Admin/Controllers/AccountController.cs b/src/admin/Bootstrap.Admin/Controllers/AccountController.cs
index e81a8dc1..0af1882b 100644
--- a/src/admin/Bootstrap.Admin/Controllers/AccountController.cs
+++ b/src/admin/Bootstrap.Admin/Controllers/AccountController.cs
@@ -11,7 +11,9 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Claims;
@@ -49,18 +51,18 @@ namespace Bootstrap.Admin.Controllers
///
/// 系统锁屏界面
///
- ///
+ ///
///
///
///
///
[HttpPost]
[IgnoreAntiforgeryToken]
- public Task Lock([FromServices]IConfiguration configuration, string userName, string password, string authType)
+ public Task Lock([FromServices]ISMSProvider provider, string userName, string password, string authType)
{
// 根据不同的登陆方式
Task ret;
- if (authType == MobileSchema) ret = Mobile(configuration, userName, password);
+ if (authType == MobileSchema) ret = Mobile(provider, userName, password);
else ret = Login(userName, password, string.Empty);
return ret;
}
@@ -84,15 +86,14 @@ namespace Bootstrap.Admin.Controllers
///
/// 短信验证登陆方法
///
- ///
+ ///
///
///
///
[HttpPost()]
- public async Task Mobile([FromServices]IConfiguration configuration, [FromQuery]string phone, [FromQuery]string code)
+ public async Task Mobile([FromServices]ISMSProvider provider, string phone, string code)
{
- var option = configuration.GetSection(nameof(SMSOptions)).Get();
- var auth = SMSHelper.Validate(phone, code, option.MD5Key);
+ var auth = provider.Validate(phone, code);
HttpContext.Log(phone, auth);
if (auth)
{
@@ -108,16 +109,26 @@ namespace Bootstrap.Admin.Controllers
Password = code,
Icon = "default.jpg",
Description = "手机用户",
- App = option.App
+ App = provider.Option.App
};
UserHelper.Save(user);
// 根据配置文件设置默认角色
- var roles = RoleHelper.Retrieves().Where(r => option.Roles.Any(rl => rl.Equals(r.RoleName, StringComparison.OrdinalIgnoreCase))).Select(r => r.Id);
+ var roles = RoleHelper.Retrieves().Where(r => provider.Option.Roles.Any(rl => rl.Equals(r.RoleName, StringComparison.OrdinalIgnoreCase))).Select(r => r.Id);
RoleHelper.SaveByUserId(user.Id, roles);
}
}
- return auth ? await SignInAsync(phone, true, MobileSchema) : View("Login", new LoginModel() { AuthFailed = true });
+ return auth ? await SignInAsync(phone, true, MobileSchema) : RedirectLogin();
+ }
+
+ private IActionResult RedirectLogin()
+ {
+ var query = Request.Query.Aggregate(new Dictionary(), (d, v) =>
+ {
+ d.Add(v.Key, v.Value.ToString());
+ return d;
+ });
+ return Redirect(QueryHelpers.AddQueryString(Request.PathBase + CookieAuthenticationDefaults.LoginPath, query));
}
///
diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/GiteeController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/GiteeController.cs
index c09aebd9..731284dd 100644
--- a/src/admin/Bootstrap.Admin/Controllers/Api/GiteeController.cs
+++ b/src/admin/Bootstrap.Admin/Controllers/Api/GiteeController.cs
@@ -36,7 +36,7 @@ namespace Bootstrap.Admin.Controllers.Api
var result = string.IsNullOrEmpty(content) ? new string[] { "unknown" } : regex.Select((m, i) => $"{labels[i]} {m.Groups[1].Value}");
return string.Join(" ", result);
});
- color = ret.StartsWith("open 0 progressing 0") ? "success" : color;
+ color = ret.StartsWith("open 0 progressing 0", StringComparison.OrdinalIgnoreCase) ? "success" : color;
return new JsonResult(new { schemaVersion = 1, label, message = ret, color });
}
diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/LoginController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/LoginController.cs
index d86420cb..4976e1bd 100644
--- a/src/admin/Bootstrap.Admin/Controllers/Api/LoginController.cs
+++ b/src/admin/Bootstrap.Admin/Controllers/Api/LoginController.cs
@@ -4,9 +4,7 @@ using Bootstrap.Security.Authentication;
using Longbow.Web.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
-using Newtonsoft.Json.Linq;
-using System.Net.Http;
+using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
namespace Bootstrap.Admin.Controllers.Api
@@ -49,19 +47,15 @@ namespace Bootstrap.Admin.Controllers.Api
///
/// 下发手机短信方法
///
- ///
- ///
+ ///
///
///
[AllowAnonymous]
[HttpPut]
- public async Task Put([FromServices]IConfiguration configuration, [FromServices]IHttpClientFactory factory, [FromQuery]string phone)
+ public async Task Put([FromServices]ISMSProvider provider, [FromQuery]string phone)
{
if (string.IsNullOrEmpty(phone)) return false;
-
- var option = configuration.GetSection(nameof(SMSOptions)).Get();
- option.Phone = phone;
- return await factory.CreateClient().SendCode(option);
+ return await provider.SendCodeAsync(phone);
}
///
diff --git a/src/admin/Bootstrap.DataAccess/Helper/SMSHelper.cs b/src/admin/Bootstrap.Admin/Extensions/SMSExtensions.cs
similarity index 58%
rename from src/admin/Bootstrap.DataAccess/Helper/SMSHelper.cs
rename to src/admin/Bootstrap.Admin/Extensions/SMSExtensions.cs
index c9d4279e..33b31aac 100644
--- a/src/admin/Bootstrap.DataAccess/Helper/SMSHelper.cs
+++ b/src/admin/Bootstrap.Admin/Extensions/SMSExtensions.cs
@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -6,59 +8,112 @@ using System.Collections.Specialized;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
-using System.Threading;
-#if NETCOREAPP3_0
using System.Text.Json;
-#else
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
-#endif
+using System.Threading;
+using System.Threading.Tasks;
-namespace Bootstrap.DataAccess
+namespace Microsoft.Extensions.DependencyInjection
{
+ ///
+ /// 短信登录扩展类
+ ///
+ public static class SMSExtensions
+ {
+ ///
+ /// 注入短信登录服务到容器中
+ ///
+ ///
+ ///
+ public static IServiceCollection AddSMSProvider(this IServiceCollection services)
+ {
+ services.AddTransient();
+ return services;
+ }
+ }
+
+ ///
+ /// 短信登录接口
+ ///
+ public interface ISMSProvider
+ {
+ ///
+ /// 手机下发验证码方法
+ ///
+ /// 手机号
+ ///
+ Task SendCodeAsync(string phoneNumber);
+
+ ///
+ /// 验证手机验证码是否正确方法
+ ///
+ /// 手机号
+ /// 验证码
+ ///
+ bool Validate(string phoneNumber, string code);
+
+ ///
+ /// 获得 配置信息
+ ///
+ SMSOptions Option { get; }
+ }
+
///
/// 手机号登陆帮助类
///
- public static class SMSHelper
+ internal class DefaultSMSProvider : ISMSProvider
{
private static ConcurrentDictionary _pool = new ConcurrentDictionary();
+ ///
+ /// 获得 短信配置信息
+ ///
+ public SMSOptions Option { get; protected set; }
+
+ private HttpClient _client;
+
+ ///
+ /// 构造函数
+ ///
+ ///
+ ///
+ public DefaultSMSProvider(IConfiguration configuration, IHttpClientFactory factory)
+ {
+ Option = configuration.GetSection().Get();
+ _client = factory.CreateClient();
+ }
+
///
/// 下发验证码方法
///
- ///
- ///
+ ///
///
- public static async System.Threading.Tasks.Task SendCode(this HttpClient client, SMSOptions option)
+ public async Task SendCodeAsync(string phoneNumber)
{
- option.Timestamp = (DateTimeOffset.UtcNow.Ticks - 621355968000000000) / 10000000;
+ Option.Timestamp = (DateTimeOffset.UtcNow.Ticks - 621355968000000000) / 10000000;
+ Option.Phone = phoneNumber;
var requestParameters = new Dictionary()
{
- { "CompanyCode", option.CompanyCode },
- { "Phone", option.Phone },
- { "TimeStamp", option.Timestamp.ToString() },
- { "Sign", option.Sign() }
+ { "CompanyCode", Option.CompanyCode },
+ { "Phone", Option.Phone },
+ { "TimeStamp", Option.Timestamp.ToString() },
+ { "Sign", Sign() }
};
- var url = QueryHelpers.AddQueryString("http://open.bluegoon.com/api/sms/sendcode", requestParameters);
- var req = await client.GetAsync(url);
+ var url = QueryHelpers.AddQueryString(Option.RequestUrl, requestParameters);
+ var req = await _client.GetAsync(url);
var content = await req.Content.ReadAsStringAsync();
-#if NETCOREAPP3_0
var result = JsonSerializer.Deserialize(content, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
-#else
- var result = JsonConvert.DeserializeObject(content, new JsonSerializerSettings() { ContractResolver = new DefaultContractResolver() });
-#endif
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));
+ _pool.AddOrUpdate(Option.Phone, key => new AutoExpireValidateCode(Option.Phone, result.Data, Option.Expires), (key, v) => v.Reset(result.Data));
ret = true;
}
else
{
new Exception("SMS Send Fail").Log(new NameValueCollection()
{
- ["UserId"] = option.Phone,
+ ["UserId"] = Option.Phone,
["url"] = url,
["content"] = content
});
@@ -71,13 +126,12 @@ namespace Bootstrap.DataAccess
///
/// 手机号
/// 验证码
- /// 密钥
///
- public static bool Validate(string phone, string code, string secret) => _pool.TryGetValue(phone, out var signKey) && Hash($"{code}{secret}") == signKey.Code;
+ public bool Validate(string phone, string code) => _pool.TryGetValue(phone, out var signKey) && Hash($"{code}{Option.MD5Key}") == signKey.Code;
- private static string Sign(this SMSOptions option)
+ private string Sign()
{
- return Hash($"{option.CompanyCode}{option.Phone}{option.Timestamp}{option.MD5Key}");
+ return Hash($"{Option.CompanyCode}{Option.Phone}{Option.Timestamp}{Option.MD5Key}");
}
private static string Hash(string data)
@@ -124,7 +178,7 @@ namespace Bootstrap.DataAccess
private CancellationTokenSource _tokenSource;
- private System.Threading.Tasks.Task RunAsync() => System.Threading.Tasks.Task.Run(() =>
+ private Task RunAsync() => Task.Run(() =>
{
_tokenSource = new CancellationTokenSource();
if (!_tokenSource.Token.WaitHandle.WaitOne(Expires)) _pool.TryRemove(Phone, out var _);
@@ -188,5 +242,10 @@ namespace Bootstrap.DataAccess
/// 获得/设置 默认授权 App
///
public string App { get; set; }
+
+ ///
+ /// 获得/设置 短信下发网关地址
+ ///
+ public string RequestUrl { get; set; } = "http://open.bluegoon.com/api/sms/sendcode";
}
}
diff --git a/src/admin/Bootstrap.Admin/Startup.cs b/src/admin/Bootstrap.Admin/Startup.cs
index 5a31d069..00f42993 100644
--- a/src/admin/Bootstrap.Admin/Startup.cs
+++ b/src/admin/Bootstrap.Admin/Startup.cs
@@ -79,6 +79,7 @@ namespace Bootstrap.Admin
option.AssumeDefaultVersionWhenUnspecified = true;
option.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("api-version"), new QueryStringApiVersionReader("api-version"));
});
+ services.AddSMSProvider();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
diff --git a/src/admin/Bootstrap.Admin/Views/Account/Login.cshtml b/src/admin/Bootstrap.Admin/Views/Account/Login.cshtml
index ed626aae..52bc062c 100644
--- a/src/admin/Bootstrap.Admin/Views/Account/Login.cshtml
+++ b/src/admin/Bootstrap.Admin/Views/Account/Login.cshtml
@@ -75,7 +75,7 @@
-
+
@@ -85,7 +85,7 @@
-
+
diff --git a/src/admin/Bootstrap.Admin/wwwroot/js/login.js b/src/admin/Bootstrap.Admin/wwwroot/js/login.js
index 37db41d7..707bbcca 100644
--- a/src/admin/Bootstrap.Admin/wwwroot/js/login.js
+++ b/src/admin/Bootstrap.Admin/wwwroot/js/login.js
@@ -132,23 +132,24 @@
var $loginSMS = $('#loginSMS');
if ($login.attr('data-demo') === 'True') {
$login.find('[name="userName"], [name="password"]').attr('data-valid', 'false');
- $login.on('submit', function (e) {
- var model = $loginType.attr('data-value');
- if (model === 'username') {
- 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.on('submit', function (e) {
+ var model = $loginType.attr('data-value');
+ if (model === 'username') {
+ if ($username.val() === '' && $password.val() === '') {
+ e.preventDefault();
+ location.href = "Gitee";
+ }
+ }
+ else {
+ // sms
+ var url = $.format('Account/Mobile{0}', location.search);
+ $login.attr('action', $.formatUrl(url));
+ return true;
+ }
+ });
+
// login type
var $loginType = $('#loginType').on('click', function (e) {
e.preventDefault();
@@ -177,7 +178,7 @@
var timeHanlder = null;
$('#btnSendCode').on('click', function () {
// validate mobile phone
- var $phone = $('#txtPhone');
+ var $phone = $('#phone');
var validator = $login.find('[data-toggle="LgbValidate"]').lgbValidator();
if (!validator.validElement($phone.get(0))) {
$phone.tooltip('show');
@@ -200,7 +201,7 @@
if (result) {
// send success
$this.text('已发送').attr('disabled', true);
- $('#smscode').removeAttr('disabled');
+ $('#code').removeAttr('disabled');
timeHanlder = setTimeout(function () {
clearTimeout(timeHanlder);
var count = 299;