You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
985 lines
38 KiB
985 lines
38 KiB
using Infrastructure.Application.Services.Settings;
|
|
using Infrastructure.Data;
|
|
using Infrastructure.Email;
|
|
using Infrastructure.Extensions;
|
|
using Infrastructure.Security;
|
|
using Infrastructure.Sms;
|
|
using Infrastructure.Web;
|
|
using Infrastructure.Web.DataAnnotations;
|
|
using IoT.Shared.Application.Domain.Entities;
|
|
using IoT.Shared.Application.Models;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Newtonsoft.Json;
|
|
using Platform.Areas.IoTCenter.Controllers;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Linq;
|
|
using System.Security.Claims;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Platform.Controllers
|
|
{
|
|
[Authorize]
|
|
public class AccountController : BaseController
|
|
{
|
|
private readonly IWebHostEnvironment _env;
|
|
private readonly IConfiguration _cfg;
|
|
private readonly ILogger<AccountController> _logger;
|
|
private readonly ISettingService _settingService;
|
|
private readonly IRepository<User> _userRepo;
|
|
private readonly IRepository<Site> _siteRepo;
|
|
private readonly IEncryptionService _encryptionService;
|
|
private readonly IEmailSender _emailSender;
|
|
private readonly ISmsSender _smsSender;
|
|
//private readonly FaceRecognitionService _frs;
|
|
|
|
public AccountController(IWebHostEnvironment env,
|
|
IConfiguration cfg,
|
|
ILogger<AccountController> logger,
|
|
ISettingService settingService,
|
|
IRepository<User> userRepo,
|
|
IRepository<Site> siteRepo,
|
|
IEncryptionService encryptionService,
|
|
IEmailSender emaliSender,
|
|
ISmsSender smsSender,
|
|
AjaxController ajax
|
|
//FaceRecognitionService frs
|
|
)
|
|
{
|
|
this._env = env;
|
|
this._cfg = cfg;
|
|
this._logger = logger;
|
|
this._settingService = settingService;
|
|
this._userRepo = userRepo;
|
|
this._siteRepo = siteRepo;
|
|
this._encryptionService = encryptionService;
|
|
this._emailSender = emaliSender;
|
|
this._smsSender = smsSender;
|
|
//this._frs = frs;
|
|
}
|
|
|
|
#region 基础设置
|
|
|
|
public IActionResult Index()
|
|
{
|
|
return View(this._siteRepo.ReadOnlyTable().ToList());
|
|
}
|
|
|
|
#endregion 基础设置
|
|
|
|
#region 注销
|
|
|
|
public IActionResult Logout(string returnUrl = null)
|
|
{
|
|
var username = User.Identity.Name;
|
|
var urls = new List<string>();
|
|
var list = this._siteRepo.ReadOnlyTable().ToList();
|
|
foreach (var site in list)
|
|
{
|
|
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
|
|
var sign = string.Concat(username, timestamp, site.Key).Md5();
|
|
var url = site.Logout
|
|
.SetParam(nameof(username), username)
|
|
.SetParam(nameof(timestamp), timestamp)
|
|
.SetParam(nameof(sign), sign);
|
|
urls.Add(url);
|
|
}
|
|
if (string.IsNullOrEmpty(returnUrl))
|
|
{
|
|
returnUrl = Url.Action("Index", "Home");
|
|
}
|
|
ViewBag.Url = returnUrl;
|
|
HttpContext.JwtSignOut();
|
|
return View("JsonpLogout", urls);
|
|
}
|
|
|
|
#endregion 注销
|
|
|
|
#region 登录
|
|
|
|
[AllowAnonymous]
|
|
[HttpGet]
|
|
public IActionResult Login(string returnUrl = null)
|
|
{
|
|
ViewData["ReturnUrl"] = returnUrl;
|
|
return Result<LoginModel>(new LoginModel());
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
public IActionResult LoginApi([FromBody] LoginModel model, string returnUrl = null)
|
|
{
|
|
return this.Login(model, returnUrl);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
public IActionResult Login(LoginModel model, string returnUrl = null)
|
|
{
|
|
var userName = model.UserName;
|
|
var password = model.Password;
|
|
var key = "";
|
|
var message = "";
|
|
if (ModelState.IsValid)
|
|
{
|
|
try
|
|
{
|
|
var user = this._userRepo.Table()
|
|
.Include(o => o.OrganUsers)
|
|
.ThenInclude(o => o.Organ)
|
|
.FirstOrDefault(o => o.UserName == userName);
|
|
if (user == null)
|
|
{
|
|
key = nameof(model.UserName);
|
|
message = "用户不存在";
|
|
}
|
|
else
|
|
{
|
|
var maxAccessFailedCount = Convert.ToInt32(this._settingService.GetValue("MaxFailedAccessAttemptsBeforeLockout"));
|
|
var lockoutEndMinutes = Convert.ToInt32(this._settingService.GetValue("DefaultAccountLockoutMinutes"));
|
|
|
|
if (user.LockoutEnabled)//对已启用登录锁定的用户,如果当前登录时间超出锁定时间,先解除锁定状态
|
|
{
|
|
if (user.LockoutEnd.HasValue && DateTime.UtcNow > user.LockoutEnd)
|
|
{
|
|
user.LockoutEnd = null;
|
|
user.AccessFailedCount = 0;
|
|
this._userRepo.SaveChanges();
|
|
}
|
|
}
|
|
var success = false;
|
|
if (user.LockoutEnabled)//对启用登录锁定的用户进行验证
|
|
{
|
|
if (user.LockoutEnd.HasValue == false)
|
|
{
|
|
if (user.PasswordHash == this._encryptionService.CreatePasswordHash(password, user.SecurityStamp))
|
|
{
|
|
user.LockoutEnd = null;
|
|
user.AccessFailedCount = 0;
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
user.AccessFailedCount += 1;
|
|
if (user.AccessFailedCount >= maxAccessFailedCount)
|
|
{
|
|
user.LockoutEnd = DateTime.UtcNow.AddMinutes(lockoutEndMinutes);
|
|
}
|
|
}
|
|
this._userRepo.SaveChanges();
|
|
}
|
|
}
|
|
else//对未启用登录锁定的用户进行验证
|
|
{
|
|
if (user.PasswordHash == this._encryptionService.CreatePasswordHash(password, user.SecurityStamp))
|
|
{
|
|
success = true;
|
|
}
|
|
}
|
|
if (success)
|
|
{
|
|
var mainOrgan = user.OrganUsers.FirstOrDefault(o => o.IsDefault)?.Organ ?? user.OrganUsers.OrderBy(o => o.Organ.Name).FirstOrDefault()?.Organ;
|
|
var timeout = model.RememberMe ? DateTime.Now.AddYears(1) : DateTime.Now.AddMinutes(Convert.ToDouble(_settingService.GetValue("AccessTokenTimeout")));
|
|
var token = Request.HttpContext.CreateJwtToken(new List<Claim> { new Claim(ClaimTypes.Name, userName) }, timeout);
|
|
if (this.IsJsonRequest())
|
|
{
|
|
return Json(this.CreateToken(userName));
|
|
}
|
|
else
|
|
{
|
|
HttpContext.JwtSignIn(model.UserName, model.RememberMe, mainOrgan?.Id.ToString());
|
|
if (string.IsNullOrEmpty(returnUrl))
|
|
{
|
|
returnUrl = Url.Action("Index", "Home");
|
|
}
|
|
ViewBag.Url = returnUrl;
|
|
var urls = new List<string>();
|
|
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);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (user.LockoutEnabled && user.LockoutEnd.HasValue)
|
|
{
|
|
key = nameof(model.UserName);
|
|
message = $"用户被锁定,请于{user.LockoutEnd.Value.ToLocalTime():HH:mm}后重试";
|
|
}
|
|
else
|
|
{
|
|
key = nameof(model.Password);
|
|
message = "密码错误";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (DbUpdateException ex)
|
|
{
|
|
ex.PrintStack();
|
|
message = ex.Message;
|
|
}
|
|
}
|
|
ModelState.AddModelError(key, message);
|
|
ViewData["ReturnUrl"] = returnUrl;
|
|
return Result<LoginModel>(model);
|
|
}
|
|
|
|
#endregion 登录
|
|
|
|
#region 注册
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult UserNameNotUsed([Required(ErrorMessage = nameof(RequiredAttribute))] string userName)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
return Json(!this._userRepo.ReadOnlyTable().Any(o => o.UserName == userName));
|
|
}
|
|
return Json("用户名不能为空");
|
|
}
|
|
|
|
#endregion 注册
|
|
|
|
#region 邮箱注册
|
|
|
|
[AllowAnonymous]
|
|
public IActionResult Register(string returnUrl = null)
|
|
{
|
|
if (Convert.ToBoolean(this._settingService.GetValue("RegisterDisabled")))
|
|
{
|
|
return RedirectTo("Index", "Home", "当前未开放注册");
|
|
}
|
|
if (User.Identity.IsAuthenticated)
|
|
{
|
|
return RedirectTo("Index", "Home", "当前已登录,请退出");
|
|
}
|
|
ViewData["ReturnUrl"] = returnUrl;
|
|
return View();
|
|
}
|
|
|
|
[HttpPost]
|
|
[AllowAnonymous]
|
|
[ValidateAntiForgeryToken]
|
|
public IActionResult Register(RegisterModel model, string returnUrl = null)
|
|
{
|
|
if (this._cfg.GetValue<bool>("RegisterDisabled"))
|
|
{
|
|
return RedirectTo("Index", "Home", "当前未开放注册");
|
|
}
|
|
if (ModelState.IsValid)
|
|
{
|
|
try
|
|
{
|
|
var user = new User().From(model);
|
|
user.SecurityStamp = this._encryptionService.CreateSalt();
|
|
user.PasswordHash = this._encryptionService.CreatePasswordHash(model.Password, user.SecurityStamp);
|
|
user.PasswordConfirmed = true;
|
|
user.EmailConfirmed = true;
|
|
this._userRepo.Add(user);
|
|
this._userRepo.SaveChanges();
|
|
if (returnUrl == null)
|
|
{
|
|
returnUrl = Url.Action("Index", "Home");
|
|
}
|
|
return RedirectTo("Login", "Account", "注册成功", new { returnUrl });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
ModelState.AddModelError("", ex.Message);
|
|
}
|
|
}
|
|
return View(model);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult EmailNotUsed([Required(ErrorMessage = nameof(RequiredAttribute))] string email)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
return Json(!this._userRepo.ReadOnlyTable().Any(o => o.Email == email));
|
|
}
|
|
return Json("邮箱不能为空");
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult SendCodeToEmail([Required(ErrorMessage = nameof(RequiredAttribute))] string email)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
try
|
|
{
|
|
string code = this.GetRandomCode();
|
|
this.SendCodeToEmailInternal(email, code);
|
|
var seconds = this.GetCaptchaSeconds();
|
|
this.HttpContext.Session.Set(CodeCaptchaModel.Key, new CodeCaptchaModel
|
|
{
|
|
ExpireDateUtc = DateTime.UtcNow.AddSeconds(seconds),
|
|
MaxErrorLimit = 5,
|
|
Captcha = code
|
|
});
|
|
return Json(new { success = true, data = seconds });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
this._logger.LogError(ex.ToString());
|
|
return Json(new { success = false, data = "邮件发送失败,请稍后重试" });
|
|
}
|
|
}
|
|
return Json(new { success = false, data = "邮箱不能为空" });
|
|
}
|
|
|
|
#endregion 邮箱注册
|
|
|
|
#region 手机号注册
|
|
|
|
[AllowAnonymous]
|
|
public IActionResult RegisterByPhoneNumber(string returnUrl = null)
|
|
{
|
|
if (this._cfg.GetValue<bool>("RegisterDisabled"))
|
|
{
|
|
return RedirectTo("Index", "Home", "当前未开放注册");
|
|
}
|
|
if (User.Identity.IsAuthenticated)
|
|
{
|
|
return RedirectTo("Index", "Home", "当前已登录,请退出后再注册");
|
|
}
|
|
ViewData["ReturnUrl"] = returnUrl;
|
|
return View();
|
|
}
|
|
|
|
[HttpPost]
|
|
[AllowAnonymous]
|
|
[ValidateAntiForgeryToken]
|
|
public IActionResult RegisterByPhoneNumber(RegisterPhoneNumberModel model, string returnUrl = null)
|
|
{
|
|
if (this._cfg.GetValue<bool>("RegisterDisabled"))
|
|
{
|
|
return RedirectTo("Index", "Home", "当前未开放注册");
|
|
}
|
|
if (ModelState.IsValid)
|
|
{
|
|
try
|
|
{
|
|
var user = new User().From(model);
|
|
user.SecurityStamp = this._encryptionService.CreateSalt();
|
|
user.PasswordHash = this._encryptionService.CreatePasswordHash(model.Password, user.SecurityStamp);
|
|
user.PasswordConfirmed = true;
|
|
user.PhoneNumberConfirmed = true;
|
|
this._userRepo.Add(user);
|
|
this._userRepo.SaveChanges();
|
|
if (returnUrl == null)
|
|
{
|
|
returnUrl = Url.Action("Index", "Home");
|
|
}
|
|
return RedirectTo("Login", "Account", "注册成功", new { returnUrl });
|
|
}
|
|
catch (DbUpdateException ex)
|
|
{
|
|
ex.PrintStack();
|
|
ModelState.AddModelError("", ex.Message);
|
|
}
|
|
}
|
|
return View(model);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult PhoneNumberNotUsed([Required(ErrorMessage = nameof(RequiredAttribute))] string phoneNumber)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
return Json(!this._userRepo.ReadOnlyTable().Any(o => o.PhoneNumber == phoneNumber));
|
|
}
|
|
return Json("邮箱不能为空");
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult SendCodeToPhoneNumber([Required(ErrorMessage = nameof(RequiredAttribute))] string phoneNumber)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
try
|
|
{
|
|
this._smsSender.Send(phoneNumber, out string code);
|
|
var seconds = this.GetCaptchaSeconds();
|
|
this.HttpContext.Session.Set(CodeCaptchaModel.Key, new CodeCaptchaModel
|
|
{
|
|
ExpireDateUtc = DateTime.UtcNow.AddSeconds(seconds),
|
|
MaxErrorLimit = 5,
|
|
Captcha = code
|
|
});
|
|
return Json(new { success = true, data = seconds });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
return Json(new { success = false, data = ex.Message });
|
|
}
|
|
}
|
|
return Json(new { success = false, data = "手机号不能为空" });
|
|
}
|
|
|
|
#endregion 手机号注册
|
|
|
|
#region 重设密码
|
|
|
|
[AllowAnonymous]
|
|
public IActionResult ForgotPassword()
|
|
{
|
|
if (User.Identity.IsAuthenticated)
|
|
{
|
|
return RedirectTo("Index", "Home", "当前已登录,请退出后重试");
|
|
}
|
|
return View();
|
|
}
|
|
|
|
[HttpPost]
|
|
[AllowAnonymous]
|
|
public IActionResult ForgotPassword(ResetPasswordModel model)
|
|
{
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == model.UserName);
|
|
if (ModelState.IsValid)
|
|
{
|
|
if (this._userRepo.Table().Any(o => o.UserName == model.UserName))
|
|
{
|
|
this.HttpContext.Session.Remove(ResetPasswordModel.Key);
|
|
user.PasswordHash = this._encryptionService.CreatePasswordHash(model.NewPassword, user.SecurityStamp);
|
|
this._userRepo.SaveChanges();
|
|
return RedirectTo(nameof(Login), rawMesage: "密码修改成功,请重新登录");
|
|
}
|
|
ModelState.AddModelError(nameof(model.UserName), "用户名不存在");
|
|
}
|
|
this.HttpContext.Session.Remove(ResetPasswordModel.Key);
|
|
ViewData.SelectList(o => model.Type, () => this.GetTypeList(user, model.Type));
|
|
//ModelState.Remove(nameof(model.CodeCaptcha));
|
|
return View(model);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult HasUser([Required(ErrorMessage = nameof(RequiredAttribute))] string userName)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
if (user != null)
|
|
{
|
|
var selectList = GetTypeList(user);
|
|
HttpContext.Response.Headers.Add("x-model", JsonConvert.SerializeObject(selectList));
|
|
HttpContext.Session.Set(ResetPasswordModel.Key, new ResetPasswordModel { UserName = userName });
|
|
HttpContext.Session.Remove(CodeCaptchaModel.Key);
|
|
return Json(true);
|
|
}
|
|
return Json("用户名不存在");
|
|
}
|
|
return Json("用户名不能为空");
|
|
}
|
|
|
|
private SelectList GetTypeList(User user, object selectedValue = null)
|
|
{
|
|
var list = new List<SelectListItem>();
|
|
if (user.EmailConfirmed)
|
|
{
|
|
list.Add(new SelectListItem { Text = Regex.Replace(user.Email, "...@", "***@"), Value = Url.Action(nameof(SendCodeToEmailForResetPassword)) });
|
|
}
|
|
var smsEnabled = Convert.ToBoolean(this._settingService.GetValue("sms"));
|
|
if (smsEnabled && user.PhoneNumberConfirmed)
|
|
{
|
|
list.Add(new SelectListItem { Text = Regex.Replace(user.PhoneNumber, "...$", "***"), Value = Url.Action(nameof(SendCodeToPhoneNumberForResetPassword)) });
|
|
}
|
|
var selectList = new SelectList(list, "Value", "Text", selectedValue);
|
|
return selectList;
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult SendCodeToEmailForResetPassword()
|
|
{
|
|
var model = HttpContext.Session.Get<ResetPasswordModel>(ResetPasswordModel.Key);
|
|
if (model != null)
|
|
{
|
|
try
|
|
{
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == model.UserName);
|
|
var email = user.Email;
|
|
string code = this.GetRandomCode();
|
|
this.SendCodeToEmailInternal(email, code);
|
|
var seconds = this.GetCaptchaSeconds();
|
|
this.HttpContext.Session.Set(CodeCaptchaModel.Key, new CodeCaptchaModel
|
|
{
|
|
ExpireDateUtc = DateTime.UtcNow.AddSeconds(seconds),
|
|
MaxErrorLimit = 5,
|
|
Captcha = code
|
|
});
|
|
return Json(new { success = true, data = seconds });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
this._logger.LogError(ex.ToString());
|
|
return Json(new { success = false, data = "邮件发送失败,请稍后重试" });
|
|
}
|
|
}
|
|
return Json(new { success = false, data = "会话已过期,请刷新页面" });
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult SendCodeToPhoneNumberForResetPassword()
|
|
{
|
|
var model = HttpContext.Session.Get<ResetPasswordModel>(ResetPasswordModel.Key);
|
|
if (model == null)
|
|
{
|
|
try
|
|
{
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == model.UserName);
|
|
var phoneNumber = user.PhoneNumber;
|
|
this._smsSender.Send(phoneNumber, out string code);
|
|
var seconds = this.GetCaptchaSeconds();
|
|
this.HttpContext.Session.Set(CodeCaptchaModel.Key, new CodeCaptchaModel
|
|
{
|
|
ExpireDateUtc = DateTime.UtcNow.AddSeconds(seconds),
|
|
MaxErrorLimit = 5,
|
|
Captcha = code
|
|
});
|
|
return Json(new { success = true, data = seconds });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
return Json(new { success = false, data = ex.Message });
|
|
}
|
|
}
|
|
return Json(new { success = false, data = "会话已过期,请刷新页面" });
|
|
}
|
|
|
|
#endregion 重设密码
|
|
|
|
#region 修改密码
|
|
|
|
public IActionResult ChangePassword()
|
|
{
|
|
return View();
|
|
}
|
|
|
|
[HttpPost]
|
|
[ValidateAntiForgeryToken]
|
|
public IActionResult ChangePassword(ChangePasswordModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
try
|
|
{
|
|
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == User.Identity.Name);
|
|
if (user.PasswordHash == this._encryptionService.CreatePasswordHash(model.OldPassword, user.SecurityStamp))
|
|
{
|
|
user.PasswordHash = this._encryptionService.CreatePasswordHash(model.NewPassword, user.SecurityStamp);
|
|
this._userRepo.SaveChanges();
|
|
return RedirectTo(rawMesage: "密码修改成功");
|
|
}
|
|
else
|
|
{
|
|
ModelState.AddModelError(nameof(model.OldPassword), "当前密码输入错误");
|
|
}
|
|
}
|
|
catch (DbUpdateException ex)
|
|
{
|
|
ex.PrintStack();
|
|
ModelState.AddModelError("", ex.Message);
|
|
}
|
|
}
|
|
return View(model);
|
|
}
|
|
|
|
#endregion 修改密码
|
|
|
|
#region 用户信息
|
|
|
|
public IActionResult UserInfo()
|
|
{
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == User.Identity.Name);
|
|
var model = user.To<EditUserInfoModel>();
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult UserInfo(EditUserInfoModel model)
|
|
{
|
|
try
|
|
{
|
|
var usreName = User.Identity.Name;
|
|
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == usreName);
|
|
user.From(model);
|
|
this._userRepo.SaveChanges();
|
|
return RedirectTo(rawMesage: "基本信息修改成功");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
ModelState.AddModelError("", ex.Message);
|
|
}
|
|
return View(model);
|
|
}
|
|
|
|
#endregion 用户信息
|
|
|
|
#region 账户安全
|
|
|
|
public IActionResult Security()
|
|
{
|
|
return View(this._userRepo.Table().FirstOrDefault(o => o.UserName == User.Identity.Name));
|
|
}
|
|
|
|
#endregion 账户安全
|
|
|
|
#region 设置修改邮箱
|
|
|
|
public IActionResult SetEmail()
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
return Validate(user);
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult SetEmail(ValidateModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
ModelState.Clear();
|
|
ViewData["HtmlAction"] = Url.Action("SetEmail2");
|
|
return View();
|
|
}
|
|
return RedirectTo("ChangeEmail", rawMesage: "请重试");
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult SetEmail2(ChangeEmailModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == userName);
|
|
user.Email = model.Email;
|
|
user.EmailConfirmed = true;
|
|
this._userRepo.SaveChanges();
|
|
return RedirectTo("Security", rawMesage: "设置邮箱成功");
|
|
}
|
|
return RedirectTo("ChangeEmail", rawMesage: "请重试");
|
|
}
|
|
|
|
public IActionResult ChangeEmail()
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
if (!user.EmailConfirmed)
|
|
{
|
|
return RedirectTo("SetEmail", rawMesage: "尚未设置邮箱");
|
|
}
|
|
return Validate(user);
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult ChangeEmail(ValidateModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
ModelState.Clear();
|
|
ViewData["HtmlAction"] = Url.Action("ChangeEmail2");
|
|
return View();
|
|
}
|
|
return RedirectTo("ChangeEmail", rawMesage: "请重试");
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult ChangeEmail2(ChangeEmailModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == userName);
|
|
user.Email = model.Email;
|
|
this._userRepo.SaveChanges();
|
|
return RedirectTo("Security", rawMesage: "更换邮箱成功");
|
|
}
|
|
return RedirectTo("ChangeEmail", rawMesage: "请重试");
|
|
}
|
|
|
|
#endregion 设置修改邮箱
|
|
|
|
#region 设置修改手机号
|
|
|
|
public IActionResult SetPhoneNumber()
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
return Validate(user);
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult SetPhoneNumber(ValidateModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
ModelState.Clear();
|
|
ViewData["HtmlAction"] = Url.Action("SetPhoneNumber2");
|
|
return View();
|
|
}
|
|
return RedirectTo("ChangePhoneNumber", rawMesage: "请重试");
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult SetPhoneNumber2(ChangePhoneNumberModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == userName);
|
|
user.PhoneNumber = model.PhoneNumber;
|
|
user.PhoneNumberConfirmed = true;
|
|
this._userRepo.SaveChanges();
|
|
return RedirectTo("Security", rawMesage: "设置手机号成功");
|
|
}
|
|
return RedirectTo("ChangePhoneNumber", rawMesage: "请重试");
|
|
}
|
|
|
|
public IActionResult ChangePhoneNumber()
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
if (!user.PhoneNumberConfirmed)
|
|
{
|
|
return RedirectTo("SetPhoneNumber", rawMesage: "尚未设置手机号");
|
|
}
|
|
return Validate(user);
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult ChangePhoneNumber(ValidateModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
ModelState.Clear();
|
|
ViewData["HtmlAction"] = Url.Action("ChangePhoneNumber2");
|
|
return View();
|
|
}
|
|
return RedirectTo("ChangePhoneNumber", rawMesage: "请重试");
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult ChangePhoneNumber2(ChangePhoneNumberModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == userName);
|
|
user.PhoneNumber = model.PhoneNumber;
|
|
this._userRepo.SaveChanges();
|
|
return RedirectTo("Security", rawMesage: "更换手机号成功");
|
|
}
|
|
return RedirectTo("ChangePhoneNumber", rawMesage: "请重试");
|
|
}
|
|
|
|
#endregion 设置修改手机号
|
|
|
|
#region 安全验证
|
|
|
|
public JsonResult SendCodeToEmailForValid()
|
|
{
|
|
try
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
var email = user.Email;
|
|
string code = this.GetRandomCode();
|
|
this.SendCodeToEmailInternal(email, code);
|
|
var seconds = this.GetCaptchaSeconds();
|
|
this.HttpContext.Session.Set(CodeCaptchaModel.Key, new CodeCaptchaModel
|
|
{
|
|
ExpireDateUtc = DateTime.UtcNow.AddSeconds(seconds),
|
|
MaxErrorLimit = 5,
|
|
Captcha = code
|
|
});
|
|
return Json(new { success = true, data = seconds });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
return Json(new { success = false, data = ex.Message });
|
|
}
|
|
}
|
|
|
|
public JsonResult SendCodeToPhoneNumberForValid()
|
|
{
|
|
try
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
var phoneNumber = user.PhoneNumber;
|
|
this._smsSender.Send(phoneNumber, out string code);
|
|
var seconds = this.GetCaptchaSeconds();
|
|
this.HttpContext.Session.Set(CodeCaptchaModel.Key, new CodeCaptchaModel
|
|
{
|
|
ExpireDateUtc = DateTime.UtcNow.AddSeconds(seconds),
|
|
MaxErrorLimit = 5,
|
|
Captcha = code
|
|
});
|
|
return Json(new { success = true, data = seconds });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
return Json(new { success = false, data = ex.Message });
|
|
}
|
|
}
|
|
|
|
private IActionResult Validate(User user)
|
|
{
|
|
var list = new List<SelectListItem>();
|
|
if (user.EmailConfirmed)
|
|
{
|
|
list.Add(new SelectListItem { Text = Regex.Replace(user.Email, "...@", "***@"), Value = Url.Action(nameof(SendCodeToEmailForValid)) });
|
|
}
|
|
var smsEnabled = Convert.ToBoolean(this._settingService.GetValue("sms"));
|
|
if (smsEnabled && user.PhoneNumberConfirmed)
|
|
{
|
|
list.Add(new SelectListItem { Text = Regex.Replace(user.PhoneNumber, "...$", "***"), Value = Url.Action(nameof(SendCodeToPhoneNumberForValid)) });
|
|
}
|
|
var selectList = new SelectList(list, "Value", "Text");
|
|
ViewData["TypeSelectList"] = selectList;
|
|
return View("Validate");
|
|
}
|
|
|
|
#endregion 安全验证
|
|
|
|
#region 权限不足
|
|
|
|
[AllowAnonymous]
|
|
public IActionResult AccessDenied(string returnUrl)
|
|
{
|
|
return View(model: returnUrl);
|
|
}
|
|
|
|
#endregion 权限不足
|
|
|
|
[AllowAnonymous]
|
|
public IActionResult ServerValid()
|
|
{
|
|
return Json(new
|
|
{
|
|
Name = this._cfg["name"],
|
|
Version = this._cfg["version"]
|
|
});
|
|
}
|
|
|
|
//[AllowAnonymous]
|
|
//[HttpPost]
|
|
//public IActionResult FaceLogin(IFormFile face)
|
|
//{
|
|
// using var stream = face.OpenReadStream();
|
|
// using var bitmap = new System.Drawing.Bitmap(stream);
|
|
// Console.WriteLine($"face length:{face.Length}");
|
|
// var userName = this._frs.FindFace(bitmap);
|
|
// if (!string.IsNullOrEmpty(userName))
|
|
// {
|
|
// var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
// if (user != null)
|
|
// {
|
|
// var list = this._siteRepo.ReadOnlyTable().ToList();
|
|
// var result = new
|
|
// {
|
|
// Code = 0,
|
|
// Token = this._jwtHelper.GetToken(new Dictionary<string, object>() { { nameof(user.UserName), user.UserName } })
|
|
// };
|
|
// return Json(result);
|
|
// }
|
|
// }
|
|
// return Json(new { Code = 1 });
|
|
//}
|
|
|
|
[AllowAnonymous]
|
|
public IActionResult HasLogin()
|
|
{
|
|
Response.Headers["Content-Type"] = "application/javascript";
|
|
return Content($"var hasLogin={(User.Identity.IsAuthenticated ? "true" : "false")}");
|
|
}
|
|
|
|
public IActionResult ChangeOrgan(string userCurrentOrganNumber, string returnUrl)
|
|
{
|
|
this.HttpContext.JwtSignOut();
|
|
this.HttpContext.JwtSignIn(User.Identity.Name, false, userCurrentOrganNumber);
|
|
return Redirect(returnUrl);
|
|
}
|
|
|
|
#region tools
|
|
|
|
private void SendCodeToEmailInternal(string email, string code)
|
|
{
|
|
var name = this._settingService.GetValue("name");
|
|
this._emailSender.SendMail(name,
|
|
this._settingService.GetValue("email:user"),
|
|
email,
|
|
$"{name}注册验证码", $"{name} 验证码:{code}",
|
|
this._settingService.GetValue("email:host"),
|
|
Convert.ToInt32(this._settingService.GetValue("email:port")),
|
|
this._settingService.GetValue("email:user"),
|
|
this._settingService.GetValue("email:password"));
|
|
}
|
|
|
|
private string GetRandomCode(int length = 4)
|
|
{
|
|
if (this._env.IsDevelopment())
|
|
{
|
|
return "1234";
|
|
}
|
|
var builder = new StringBuilder();
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
var random = new byte[1];
|
|
using var rg = RandomNumberGenerator.Create();
|
|
rg.GetBytes(random);
|
|
builder.Append(new Random(Convert.ToInt32(random[0])).Next(0, 9));
|
|
}
|
|
return builder.ToString();
|
|
}
|
|
|
|
private int GetCaptchaSeconds()
|
|
{
|
|
return Convert.ToInt32(this._settingService.GetValue("CaptchaSeconds"));
|
|
}
|
|
|
|
private object CreateToken(String userName)
|
|
{
|
|
return new
|
|
{
|
|
AccessToken = Request.HttpContext.CreateJwtToken(new List<Claim> { new Claim(ClaimTypes.Name, userName) }, DateTime.Now.AddMinutes(Convert.ToDouble(_settingService.GetValue("AccessTokenTimeout")))),
|
|
RefreshToken = Request.HttpContext.CreateJwtToken(new List<Claim> { new Claim(ClaimTypes.Name, userName) }, DateTime.Now.AddMinutes(Convert.ToDouble(_settingService.GetValue("RefreshTokenTimeout")))),
|
|
};
|
|
}
|
|
|
|
#endregion tools
|
|
}
|
|
}
|