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.
913 lines
34 KiB
913 lines
34 KiB
using Application.Domain.Entities;
|
|
using Application.Models;
|
|
using Infrastructure.Data;
|
|
using Infrastructure.Email;
|
|
using Infrastructure.Extensions;
|
|
using Infrastructure.Jwt;
|
|
using Infrastructure.Resources;
|
|
using Infrastructure.Security;
|
|
using Infrastructure.Sms;
|
|
using Infrastructure.Web;
|
|
using Infrastructure.Web.DataAnnotations;
|
|
using JWT.Algorithms;
|
|
using JWT.Builder;
|
|
using Microsoft.AspNetCore.Authentication;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Localization;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace UserCenter.Controllers
|
|
{
|
|
[Authorize]
|
|
public class AccountController : BaseController
|
|
{
|
|
private readonly IConfiguration _cfg;
|
|
private readonly IJwtHelper _jwtHelper;
|
|
private readonly IRepository<User> _userRepo;
|
|
private readonly IRepository<Site> _siteRepo;
|
|
private readonly IStringLocalizer<Resource> _localizer;
|
|
private readonly IEncryptionService _encryptionService;
|
|
private readonly IEmailSender _emailSender;
|
|
private readonly ISmsSender _smsSender;
|
|
|
|
public AccountController(IConfiguration cfg,
|
|
IJwtHelper jwtHelper,
|
|
IRepository<User> userRepo,
|
|
IRepository<Site> siteRepo,
|
|
IEncryptionService encryptionService,
|
|
IStringLocalizer<Resource> localizer,
|
|
IEmailSender emaliSender,
|
|
ISmsSender smsSender)
|
|
{
|
|
this._cfg = cfg;
|
|
this._jwtHelper = jwtHelper;
|
|
this._userRepo = userRepo;
|
|
this._siteRepo = siteRepo;
|
|
this._encryptionService = encryptionService;
|
|
this._localizer = localizer;
|
|
this._emailSender = emaliSender;
|
|
this._smsSender = smsSender;
|
|
}
|
|
|
|
#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.SignOutAsync();
|
|
return View("JsonpLogout", urls);
|
|
}
|
|
|
|
#endregion 注销
|
|
|
|
#region 登录
|
|
|
|
[AllowAnonymous]
|
|
[HttpGet]
|
|
public IActionResult Login(string returnUrl = null)
|
|
{
|
|
ViewData["ReturnUrl"] = returnUrl;
|
|
return View();
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
public IActionResult Login(LoginModel model, string returnUrl = null)
|
|
{
|
|
return this.LoginInternal(model, false, returnUrl);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public IActionResult AppLogin(LoginModel model)
|
|
{
|
|
return this.LoginInternal(model, true);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public IActionResult LoginInternal(LoginModel model, bool isAppLogin, string returnUrl = null)
|
|
{
|
|
var userName = model.UserName;
|
|
var password = model.Password;
|
|
var key = "";
|
|
var message = "";
|
|
if (ModelState.IsValid)
|
|
{
|
|
try
|
|
{
|
|
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == userName);
|
|
if (user == null)
|
|
{
|
|
key = nameof(model.UserName);
|
|
message = "用户不存在";
|
|
}
|
|
else
|
|
{
|
|
var maxAccessFailedCount = this._cfg.GetValue<int>("MaxFailedAccessAttemptsBeforeLockout");
|
|
var lockoutEndMinutes = this._cfg.GetValue<int>("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 list = this._siteRepo.ReadOnlyTable().ToList();
|
|
if (isAppLogin)
|
|
{
|
|
return Json(new
|
|
{
|
|
Code = 0,
|
|
Token = this._jwtHelper.GetToken(new Dictionary<string, object>() { { nameof(user.UserName), user.UserName } }),
|
|
user.NickName,
|
|
Title = this._cfg["name"],
|
|
IoTServer = list.FirstOrDefault(o => o.Name == "物联网平台").Home
|
|
}
|
|
);
|
|
}
|
|
else
|
|
{
|
|
var userPermissions = this._userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
|
|
.SelectMany(o => o.UserRoles)
|
|
.Select(o => o.Role)
|
|
.SelectMany(o => o.RolePermissions)
|
|
.Select(o => o.Permission.Number)
|
|
.ToList();
|
|
HttpContext.SignIn(model.UserName, userPermissions, model.RememberMe);
|
|
if (string.IsNullOrEmpty(returnUrl))
|
|
{
|
|
returnUrl = Url.Action("Index", "Home");
|
|
}
|
|
ViewBag.Url = Url.IsLocalUrl(returnUrl) ? Url.GetFullUrl("~") : returnUrl;
|
|
var urls = new List<string>();
|
|
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(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().ToString("HH:mm")}后重试";
|
|
}
|
|
else
|
|
{
|
|
key = nameof(model.Password);
|
|
message = "密码错误";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
message = ex.Message;
|
|
}
|
|
}
|
|
if (isAppLogin)
|
|
{
|
|
return Json(new { Code = 1, Key = key, Message = message });
|
|
}
|
|
else
|
|
{
|
|
ModelState.AddModelError(key, message);
|
|
ViewData["ReturnUrl"] = returnUrl;
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
#endregion 登录
|
|
|
|
#region 注册
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult UserNameNotUsed([Required]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 (this.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]string email)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
return Json(!this._userRepo.ReadOnlyTable().Any(o => o.Email == email));
|
|
}
|
|
return Json("邮箱不能为空");
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult SendCodeToEmail([Required]string email)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
try
|
|
{
|
|
string code = this.GetRandomCode();
|
|
this.SendCodeToEmail(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 });
|
|
}
|
|
}
|
|
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 (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
ModelState.AddModelError("", ex.Message);
|
|
}
|
|
}
|
|
return View(model);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult PhoneNumberNotUsed([Required]string phoneNumber)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
return Json(!this._userRepo.ReadOnlyTable().Any(o => o.PhoneNumber == phoneNumber));
|
|
}
|
|
return Json("邮箱不能为空");
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult SendCodeToPhoneNumber([Required]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)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
if (this._userRepo.ReadOnlyTable().Any(o => o.UserName == model.UserName))
|
|
{
|
|
this.HttpContext.Session.Remove(ResetPasswordModel.Key);
|
|
return RedirectTo(nameof(Login), message: "密码修改成功,请重新登录");
|
|
}
|
|
ModelState.AddModelError(nameof(model.UserName), "用户名不存在");
|
|
}
|
|
this.HttpContext.Session.Remove(ResetPasswordModel.Key);
|
|
return RedirectTo(nameof(ForgotPassword), message: "请重试");
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
public JsonResult HasUser([Required]string userName)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
if (user != null)
|
|
{
|
|
var list = new List<SelectListItem>();
|
|
if (user.EmailConfirmed)
|
|
{
|
|
list.Add(new SelectListItem { Text = Regex.Replace(user.Email, "...@", "***@"), Value = Url.Action(nameof(SendCodeToEmailForResetPassword)) });
|
|
}
|
|
if (user.PhoneNumberConfirmed)
|
|
{
|
|
list.Add(new SelectListItem { Text = Regex.Replace(user.PhoneNumber, "...$", "***"), Value = Url.Action(nameof(SendCodeToPhoneNumberForResetPassword)) });
|
|
}
|
|
var selectList = new SelectList(list, "Value", "Text");
|
|
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("用户名不能为空");
|
|
}
|
|
|
|
[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.SendCodeToEmail(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 });
|
|
}
|
|
}
|
|
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(message: "密码修改成功");
|
|
}
|
|
else
|
|
{
|
|
ModelState.AddModelError(nameof(model.OldPassword), "当前密码输入错误");
|
|
}
|
|
}
|
|
catch (Exception 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(message: "基本信息修改成功");
|
|
}
|
|
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", message: "请重试");
|
|
}
|
|
|
|
[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", message: "设置邮箱成功");
|
|
}
|
|
return RedirectTo("ChangeEmail", message: "请重试");
|
|
}
|
|
|
|
public IActionResult ChangeEmail()
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
if (!user.EmailConfirmed)
|
|
{
|
|
return RedirectTo("SetEmail", message: "尚未设置邮箱");
|
|
}
|
|
return Validate(user);
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult ChangeEmail(ValidateModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
ModelState.Clear();
|
|
ViewData["HtmlAction"] = Url.Action("ChangeEmail2");
|
|
return View();
|
|
}
|
|
return RedirectTo("ChangeEmail", message: "请重试");
|
|
}
|
|
|
|
[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", message: "更换邮箱成功");
|
|
}
|
|
return RedirectTo("ChangeEmail", message: "请重试");
|
|
}
|
|
|
|
#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", message: "请重试");
|
|
}
|
|
|
|
[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", message: "设置手机号成功");
|
|
}
|
|
return RedirectTo("ChangePhoneNumber", message: "请重试");
|
|
}
|
|
|
|
public IActionResult ChangePhoneNumber()
|
|
{
|
|
var userName = User.Identity.Name;
|
|
var user = this._userRepo.ReadOnlyTable().FirstOrDefault(o => o.UserName == userName);
|
|
if (!user.PhoneNumberConfirmed)
|
|
{
|
|
return RedirectTo("SetPhoneNumber", message: "尚未设置手机号");
|
|
}
|
|
return Validate(user);
|
|
}
|
|
|
|
[HttpPost]
|
|
public IActionResult ChangePhoneNumber(ValidateModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
ModelState.Clear();
|
|
ViewData["HtmlAction"] = Url.Action("ChangePhoneNumber2");
|
|
return View();
|
|
}
|
|
return RedirectTo("ChangePhoneNumber", message: "请重试");
|
|
}
|
|
|
|
[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", message: "更换手机号成功");
|
|
}
|
|
return RedirectTo("ChangePhoneNumber", message: "请重试");
|
|
}
|
|
|
|
#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.SendCodeToEmail(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)) });
|
|
}
|
|
if (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 权限不足
|
|
|
|
#region tools
|
|
|
|
private void SendCodeToEmail(string email, string code)
|
|
{
|
|
this._emailSender.SendMail(this._cfg["Name"], this._cfg["EmailUser"], email, $"{ this._cfg["Name"]}注册验证码", $"{this._cfg["Name"]} 验证码:{code}", this._cfg["EmailHost"], this._cfg.GetValue<int>("EmailPort"), this._cfg["EmailUser"], this._cfg["EmailPassword"]);
|
|
}
|
|
|
|
private string GetRandomCode(int length = 4)
|
|
{
|
|
var builder = new StringBuilder();
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
var random = new byte[1];
|
|
RandomNumberGenerator.Create().GetBytes(random);
|
|
builder.Append(new Random(Convert.ToInt32(random[0])).Next(0, 9));
|
|
}
|
|
return builder.ToString();
|
|
}
|
|
|
|
private bool RegisterDisabled()
|
|
{
|
|
return this._cfg.GetValue<bool>("RegisterDisabled");
|
|
}
|
|
|
|
private int GetCaptchaSeconds()
|
|
{
|
|
return this._cfg.GetValue<int>("CaptchaSeconds");
|
|
}
|
|
|
|
#endregion tools
|
|
}
|
|
} |