diff --git a/projects/Infrastructure/Extensions/ControllerExtensions.cs b/projects/Infrastructure/Extensions/ControllerExtensions.cs index d255b390..ab927b5c 100644 --- a/projects/Infrastructure/Extensions/ControllerExtensions.cs +++ b/projects/Infrastructure/Extensions/ControllerExtensions.cs @@ -297,6 +297,11 @@ namespace Infrastructure.Extensions } } + public static bool IsJsonRequest(this ControllerBase controller) + { + return controller.Request.Headers["accept"].ToString().Contains("json", StringComparison.OrdinalIgnoreCase); + } + public static string GetErrorMessage(this ValidationAttribute attribute, IStringLocalizer localizer, params string[] args) { var localizedString = localizer.GetString(attribute.GetType().Name); diff --git a/projects/Infrastructure/Web/Mvc/BaseController.cs b/projects/Infrastructure/Web/Mvc/BaseController.cs index a12630bc..13ad99bd 100644 --- a/projects/Infrastructure/Web/Mvc/BaseController.cs +++ b/projects/Infrastructure/Web/Mvc/BaseController.cs @@ -1,4 +1,10 @@ +using Infrastructure.Extensions; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Linq; namespace Infrastructure.Web { @@ -17,5 +23,20 @@ namespace Infrastructure.Web ViewBag.Url = returnUrl; return View("Redirect"); } + + protected IActionResult Result(object model) + { + if (this.IsJsonRequest()) + { + return Json(new + { + schema = this.GetJsonSchema(), + model, + errors = ModelState.Where(o => o.Value.ValidationState == ModelValidationState.Invalid), + data = ViewData + }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver(), ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); + } + return View(model); + } } } \ No newline at end of file diff --git a/projects/Infrastructure/Web/Mvc/CrudController.cs b/projects/Infrastructure/Web/Mvc/CrudController.cs index 46d4d19b..51daa5e8 100644 --- a/projects/Infrastructure/Web/Mvc/CrudController.cs +++ b/projects/Infrastructure/Web/Mvc/CrudController.cs @@ -317,23 +317,13 @@ namespace Infrastructure.Web.Mvc [ApiExplorerSettings(IgnoreApi = true)] protected IActionResult Result(object model) { - if (this.Request.Headers["accept"].ToString().Contains("json", StringComparison.OrdinalIgnoreCase)) - { - return Json(new - { - schema = this.GetJsonSchema(), - model, - errors = ModelState.Where(o => o.Value.ValidationState == ModelValidationState.Invalid), - data = ViewData - }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); - } - return View(model); + return Result(model); } [ApiExplorerSettings(IgnoreApi = true)] protected IActionResult Success() { - if (this.Request.Headers["accept"].ToString().Contains("json", StringComparison.OrdinalIgnoreCase)) + if (this.IsJsonRequest()) { return this.NoContent(); } @@ -343,7 +333,7 @@ namespace Infrastructure.Web.Mvc [ApiExplorerSettings(IgnoreApi = true)] protected IActionResult Error(string message) { - if (this.Request.Headers["accept"].ToString().Contains("json", StringComparison.OrdinalIgnoreCase)) + if (this.IsJsonRequest()) { return this.Problem(message); } diff --git a/projects/Infrastructure/Web/Mvc/DynamicController/GenericController.cs b/projects/Infrastructure/Web/Mvc/DynamicController/GenericController.cs index 6fe79106..2338138c 100644 --- a/projects/Infrastructure/Web/Mvc/DynamicController/GenericController.cs +++ b/projects/Infrastructure/Web/Mvc/DynamicController/GenericController.cs @@ -320,7 +320,7 @@ namespace Infrastructure.Web.Mvc [ApiExplorerSettings(IgnoreApi = true)] private IActionResult Result(object model) { - return this.Request.Headers["accept"].ToString().Contains("json", StringComparison.OrdinalIgnoreCase) ? Json(model) as IActionResult : View(model); + return this.IsJsonRequest() ? Json(model) as IActionResult : View(model); } public IActionResult GetJsonSchema() diff --git a/projects/IoT.Shared/Areas/Admin/Controlls/CommandController.cs b/projects/IoT.Shared/Areas/Admin/Controlls/CommandController.cs index 311f6985..2da5da90 100644 --- a/projects/IoT.Shared/Areas/Admin/Controlls/CommandController.cs +++ b/projects/IoT.Shared/Areas/Admin/Controlls/CommandController.cs @@ -6,8 +6,11 @@ using Infrastructure.Data; using Infrastructure.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; using NPOI.SS.Formula.Functions; using System; using System.Collections.Generic; @@ -53,6 +56,16 @@ namespace IoT.Shared.Areas.Admin.Controlls public IActionResult Api(Guid apiId, Guid deviceId) { var model = this.GetParameters(apiId, deviceId, null); + if (this.IsJsonRequest()) + { + return Json(new + { + schema = this.GetJsonSchema(), + model, + errors = ModelState.Where(o => o.Value.ValidationState == ModelValidationState.Invalid), + data = ViewData + }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver(), ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); + } return PartialView("_Api", model); } diff --git a/projects/UserCenter/Controllers/AccountController.cs b/projects/UserCenter/Controllers/AccountController.cs index 3544f109..d5fb0db9 100644 --- a/projects/UserCenter/Controllers/AccountController.cs +++ b/projects/UserCenter/Controllers/AccountController.cs @@ -101,7 +101,14 @@ namespace UserCenter.Controllers public IActionResult Login(string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; - return View(); + return Result(new LoginModel()); + } + + [AllowAnonymous] + [HttpPost] + public IActionResult LoginApi([FromBody] LoginModel model, string returnUrl = null) + { + return this.Login(model, returnUrl); } [AllowAnonymous] @@ -167,30 +174,37 @@ namespace UserCenter.Controllers } if (success) { - HttpContext.JwtSignIn(model.UserName, model.RememberMe, _cfg); - if (string.IsNullOrEmpty(returnUrl)) + if (this.IsJsonRequest()) { - returnUrl = Url.Action("Index", "Home"); + return Json(this.CreateToken(userName)); } - ViewBag.Url = returnUrl; - var urls = new List(); - var list = this._siteRepo.ReadOnlyTable().ToList(); - foreach (var site in list) + else { - var username = user.UserName; - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(); - var sign = string.Concat(userName, timestamp, site.Key).Md5(); - var url = site.Login - .SetParam(nameof(username), username) - .SetParam(nameof(user.NickName), user.NickName) - .SetParam(nameof(user.Avatar), user.Avatar) - .SetParam(nameof(timestamp), timestamp) - .SetParam("rememberme", model.RememberMe) - .SetParam(nameof(sign), sign); - urls.Add(url); + HttpContext.JwtSignIn(model.UserName, model.RememberMe, _cfg); + if (string.IsNullOrEmpty(returnUrl)) + { + returnUrl = Url.Action("Index", "Home"); + } + ViewBag.Url = returnUrl; + var urls = new List(); + var list = this._siteRepo.ReadOnlyTable().ToList(); + foreach (var site in list) + { + var username = user.UserName; + var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(); + var sign = string.Concat(userName, timestamp, site.Key).Md5(); + var url = site.Login + .SetParam(nameof(username), username) + .SetParam(nameof(user.NickName), user.NickName) + .SetParam(nameof(user.Avatar), user.Avatar) + .SetParam(nameof(timestamp), timestamp) + .SetParam("rememberme", model.RememberMe) + .SetParam(nameof(sign), sign); + urls.Add(url); + } + Response.Headers.Remove("Location"); + return View("JsonpLogin", urls); } - Response.Headers.Remove("Location"); - return View("JsonpLogin", urls); } else { @@ -215,7 +229,7 @@ namespace UserCenter.Controllers } ModelState.AddModelError(key, message); ViewData["ReturnUrl"] = returnUrl; - return View(model); + return Result(model); } #endregion 登录 @@ -920,6 +934,15 @@ namespace UserCenter.Controllers return this._cfg.GetValue("CaptchaSeconds"); } + private object CreateToken(String userName) + { + return new + { + AccessToken = Request.HttpContext.GetToken(userName, _cfg, DateTime.Now.AddMinutes(Convert.ToDouble(_settingService.GetSetting("AccessTokenTimeout").Value))), + RefreshToken = Request.HttpContext.GetToken(userName, _cfg, DateTime.Now.AddMinutes(Convert.ToDouble(_settingService.GetSetting("RefreshTokenTimeout").Value))), + }; + } + #endregion tools } } \ No newline at end of file diff --git a/projects/WebMVC/wwwroot/js/axios.js b/projects/WebMVC/wwwroot/js/axios.js index d4a398e4..f0f7ef7d 100644 --- a/projects/WebMVC/wwwroot/js/axios.js +++ b/projects/WebMVC/wwwroot/js/axios.js @@ -21,7 +21,7 @@ axios.interceptors.response.use(function (response) { loading.hide(); return response; }, function (error) { - console.error(error.response); + console.error(error); if (error.response.status === 401 && error.config.url.indexOf('refreshToken') === -1) { var url = apiHost + '/UserCenter/api/v1/token/refreshToken'; var data = '"' + store.state.token.refreshToken + '"'; diff --git a/projects/WebMVC/wwwroot/js/form.js b/projects/WebMVC/wwwroot/js/form.js index b617984e..848490c1 100644 --- a/projects/WebMVC/wwwroot/js/form.js +++ b/projects/WebMVC/wwwroot/js/form.js @@ -9,6 +9,7 @@ 'display-html', 'display-cron', 'edit-string', + 'edit-password', 'edit-boolean', 'edit-imageurl', 'edit-integer', diff --git a/projects/WebMVC/wwwroot/js/route.js b/projects/WebMVC/wwwroot/js/route.js index fcd87b20..22551892 100644 --- a/projects/WebMVC/wwwroot/js/route.js +++ b/projects/WebMVC/wwwroot/js/route.js @@ -8,7 +8,10 @@ router.beforeEach((to, from, next) => { isAuthenticated = jwt.exp * 1000 >= new Date().getTime(); } if (!isAuthenticated) { - router.push('/router/login.html'); + store.commit('logout'); + setTimeout(function () { + router.push('/router/login.html'); + }, 1000); return; } } diff --git a/projects/WebMVC/wwwroot/js/state.js b/projects/WebMVC/wwwroot/js/state.js index cd74825c..7b53374e 100644 --- a/projects/WebMVC/wwwroot/js/state.js +++ b/projects/WebMVC/wwwroot/js/state.js @@ -11,10 +11,17 @@ const store = new Vuex.Store({ setState(state,data) { state[data.key] = data.value; }, + login(state, data) { + localStorage.setItem('accessToken', data.accessToken); + localStorage.setItem('refreshToken', data.refreshToken); + state.token.accessToken = data.accessToken; + state.token.refreshToken = data.refreshToken; + }, logout(state) { localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); - state.token = null; + state.token.accessToken = null; + state.token.refreshToken = null; } } }); \ No newline at end of file diff --git a/projects/WebMVC/wwwroot/router/admin/command/detail.html b/projects/WebMVC/wwwroot/router/admin/command/detail.html new file mode 100644 index 00000000..f5789d80 --- /dev/null +++ b/projects/WebMVC/wwwroot/router/admin/command/detail.html @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/projects/WebMVC/wwwroot/router/admin/command/edit.html b/projects/WebMVC/wwwroot/router/admin/command/edit.html new file mode 100644 index 00000000..99d55e01 --- /dev/null +++ b/projects/WebMVC/wwwroot/router/admin/command/edit.html @@ -0,0 +1,290 @@ + + \ No newline at end of file diff --git a/projects/WebMVC/wwwroot/router/admin/command/index.html b/projects/WebMVC/wwwroot/router/admin/command/index.html new file mode 100644 index 00000000..88395f79 --- /dev/null +++ b/projects/WebMVC/wwwroot/router/admin/command/index.html @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/projects/WebMVC/wwwroot/router/login.html b/projects/WebMVC/wwwroot/router/login.html index 18edac85..3afaf13d 100644 --- a/projects/WebMVC/wwwroot/router/login.html +++ b/projects/WebMVC/wwwroot/router/login.html @@ -1,43 +1,160 @@  \ No newline at end of file diff --git a/projects/WebMVC/wwwroot/router/shared/layout.html b/projects/WebMVC/wwwroot/router/shared/layout.html index fb9bedd8..cbf4555e 100644 --- a/projects/WebMVC/wwwroot/router/shared/layout.html +++ b/projects/WebMVC/wwwroot/router/shared/layout.html @@ -34,7 +34,7 @@ {{data.name}} -