|
|
using Application.Domain.Entities;
|
|
|
using Application.Models;
|
|
|
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 Microsoft.AspNetCore.Authorization;
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
using Microsoft.Extensions.Configuration;
|
|
|
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 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(IConfiguration cfg,
|
|
|
ISettingService settingService,
|
|
|
IRepository<User> userRepo,
|
|
|
IRepository<Site> siteRepo,
|
|
|
IEncryptionService encryptionService,
|
|
|
IEmailSender emaliSender,
|
|
|
ISmsSender smsSender
|
|
|
//FaceRecognitionService frs
|
|
|
)
|
|
|
{
|
|
|
this._cfg = cfg;
|
|
|
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 View();
|
|
|
}
|
|
|
|
|
|
[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().FirstOrDefault(o => o.UserName == userName);
|
|
|
if (user == null)
|
|
|
{
|
|
|
key = nameof(model.UserName);
|
|
|
message = "用户ä¸<C3A4>å˜åœ¨";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var maxAccessFailedCount = Convert.ToInt32(this._settingService.GetSetting("MaxFailedAccessAttemptsBeforeLockout").Value);
|
|
|
var lockoutEndMinutes = Convert.ToInt32(this._settingService.GetSetting("DefaultAccountLockoutMinutes").Value);
|
|
|
|
|
|
if (user.LockoutEnabled)//对已å<C2B2>¯ç”¨ç™»å½•é”<C3A9>定的用户,如果当å‰<C3A5>登录时间超出é”<C3A9>定时间,先解除é”<C3A9>定状æ€<C3A6>
|
|
|
{
|
|
|
if (user.LockoutEnd.HasValue && DateTime.UtcNow > user.LockoutEnd)
|
|
|
{
|
|
|
user.LockoutEnd = null;
|
|
|
user.AccessFailedCount = 0;
|
|
|
this._userRepo.SaveChanges();
|
|
|
}
|
|
|
}
|
|
|
var success = false;
|
|
|
if (user.LockoutEnabled)//对å<C2B9>¯ç”¨ç™»å½•é”<C3A9>定的用户进行验è¯<C3A8>
|
|
|
{
|
|
|
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//对未å<C2AA>¯ç”¨ç™»å½•é”<C3A9>定的用户进行验è¯<C3A8>
|
|
|
{
|
|
|
if (user.PasswordHash == this._encryptionService.CreatePasswordHash(password, user.SecurityStamp))
|
|
|
{
|
|
|
success = true;
|
|
|
}
|
|
|
}
|
|
|
if (success)
|
|
|
{
|
|
|
HttpContext.JwtSignIn(model.UserName, model.RememberMe, _cfg);
|
|
|
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 = $"用户被é”<C3A9>定,请于{user.LockoutEnd.Value.ToLocalTime():HH:mm}å<>Žé‡<C3A9>试";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
key = nameof(model.Password);
|
|
|
message = "密ç <C3A7>错误";
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (DbUpdateException ex)
|
|
|
{
|
|
|
ex.PrintStack();
|
|
|
message = ex.Message;
|
|
|
}
|
|
|
}
|
|
|
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("用户å<C2B7><C3A5>ä¸<C3A4>能为空");
|
|
|
}
|
|
|
|
|
|
#endregion 注册
|
|
|
|
|
|
#region 邮箱注册
|
|
|
|
|
|
[AllowAnonymous]
|
|
|
public IActionResult Register(string returnUrl = null)
|
|
|
{
|
|
|
if (this.RegisterDisabled())
|
|
|
{
|
|
|
return RedirectTo("Index", "Home", "当å‰<C3A5>未开放注册");
|
|
|
}
|
|
|
if (User.Identity.IsAuthenticated)
|
|
|
{
|
|
|
return RedirectTo("Index", "Home", "当å‰<C3A5>已登录,请退出");
|
|
|
}
|
|
|
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", "当å‰<C3A5>未开放注册");
|
|
|
}
|
|
|
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", "注册æˆ<C3A6>功", 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("邮箱ä¸<C3A4>能为空");
|
|
|
}
|
|
|
|
|
|
[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 = "邮箱ä¸<C3A4>能为空" });
|
|
|
}
|
|
|
|
|
|
#endregion 邮箱注册
|
|
|
|
|
|
#region 手机å<C2BA>·æ³¨å†Œ
|
|
|
|
|
|
[AllowAnonymous]
|
|
|
public IActionResult RegisterByPhoneNumber(string returnUrl = null)
|
|
|
{
|
|
|
if (this._cfg.GetValue<bool>("RegisterDisabled"))
|
|
|
{
|
|
|
return RedirectTo("Index", "Home", "当å‰<C3A5>未开放注册");
|
|
|
}
|
|
|
if (User.Identity.IsAuthenticated)
|
|
|
{
|
|
|
return RedirectTo("Index", "Home", "当å‰<C3A5>已登录,请退出å<C2BA>Žå†<C3A5>注册");
|
|
|
}
|
|
|
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", "当å‰<C3A5>未开放注册");
|
|
|
}
|
|
|
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", "注册æˆ<C3A6>功", new { returnUrl });
|
|
|
}
|
|
|
catch (DbUpdateException 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("邮箱ä¸<C3A4>能为空");
|
|
|
}
|
|
|
|
|
|
[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 = "手机å<C2BA>·ä¸<C3A4>能为空" });
|
|
|
}
|
|
|
|
|
|
#endregion 手机å<C2BA>·æ³¨å†Œ
|
|
|
|
|
|
#region é‡<C3A9>设密ç <C3A7>
|
|
|
|
|
|
[AllowAnonymous]
|
|
|
public IActionResult ForgotPassword()
|
|
|
{
|
|
|
if (User.Identity.IsAuthenticated)
|
|
|
{
|
|
|
return RedirectTo("Index", "Home", "当å‰<C3A5>已登录,请退出å<C2BA>Žé‡<C3A9>试");
|
|
|
}
|
|
|
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), rawMesage: "密ç <C3A7>修改æˆ<C3A6>功,请é‡<C3A9>新登录");
|
|
|
}
|
|
|
ModelState.AddModelError(nameof(model.UserName), "用户å<C2B7><C3A5>ä¸<C3A4>å˜åœ¨");
|
|
|
}
|
|
|
this.HttpContext.Session.Remove(ResetPasswordModel.Key);
|
|
|
return RedirectTo(nameof(ForgotPassword), rawMesage: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
[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)) });
|
|
|
}
|
|
|
var smsEnabled = Convert.ToBoolean(this._settingService.GetSetting("sms").Value);
|
|
|
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");
|
|
|
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("用户å<C2B7><C3A5>ä¸<C3A4>å˜åœ¨");
|
|
|
}
|
|
|
return Json("用户å<C2B7><C3A5>ä¸<C3A4>能为空");
|
|
|
}
|
|
|
|
|
|
[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 = "会è¯<C3A8>已过期,请刷新页é<C2B5>¢" });
|
|
|
}
|
|
|
|
|
|
[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 = "会è¯<C3A8>已过期,请刷新页é<C2B5>¢" });
|
|
|
}
|
|
|
|
|
|
#endregion é‡<C3A9>设密ç <C3A7>
|
|
|
|
|
|
#region 修改密ç <C3A7>
|
|
|
|
|
|
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: "密ç <C3A7>修改æˆ<C3A6>功");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
ModelState.AddModelError(nameof(model.OldPassword), "当å‰<C3A5>密ç <C3A7>输入错误");
|
|
|
}
|
|
|
}
|
|
|
catch (DbUpdateException ex)
|
|
|
{
|
|
|
ex.PrintStack();
|
|
|
ModelState.AddModelError("", ex.Message);
|
|
|
}
|
|
|
}
|
|
|
return View(model);
|
|
|
}
|
|
|
|
|
|
#endregion 修改密ç <C3A7>
|
|
|
|
|
|
#region 用户信æ<C2A1>¯
|
|
|
|
|
|
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: "基本信æ<C2A1>¯ä¿®æ”¹æˆ<C3A6>功");
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
ex.PrintStack();
|
|
|
ModelState.AddModelError("", ex.Message);
|
|
|
}
|
|
|
return View(model);
|
|
|
}
|
|
|
|
|
|
#endregion 用户信æ<C2A1>¯
|
|
|
|
|
|
#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: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
[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: "设置邮箱æˆ<C3A6>功");
|
|
|
}
|
|
|
return RedirectTo("ChangeEmail", rawMesage: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
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: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
[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: "æ›´æ<C2B4>¢é‚®ç®±æˆ<C3A6>功");
|
|
|
}
|
|
|
return RedirectTo("ChangeEmail", rawMesage: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
#endregion 设置修改邮箱
|
|
|
|
|
|
#region 设置修改手机å<C2BA>·
|
|
|
|
|
|
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: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
[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: "设置手机å<C2BA>·æˆ<C3A6>功");
|
|
|
}
|
|
|
return RedirectTo("ChangePhoneNumber", rawMesage: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
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: "尚未设置手机å<C2BA>·");
|
|
|
}
|
|
|
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: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
[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: "æ›´æ<C2B4>¢æ‰‹æœºå<C2BA>·æˆ<C3A6>功");
|
|
|
}
|
|
|
return RedirectTo("ChangePhoneNumber", rawMesage: "请é‡<C3A9>试");
|
|
|
}
|
|
|
|
|
|
#endregion 设置修改手机å<C2BA>·
|
|
|
|
|
|
#region 安全验è¯<C3A8>
|
|
|
|
|
|
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)) });
|
|
|
}
|
|
|
var smsEnabled = Convert.ToBoolean(this._settingService.GetSetting("sms").Value);
|
|
|
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 安全验è¯<C3A8>
|
|
|
|
|
|
#region æ<>ƒé™<C3A9>ä¸<C3A4>è¶³
|
|
|
|
|
|
[AllowAnonymous]
|
|
|
public IActionResult AccessDenied(string returnUrl)
|
|
|
{
|
|
|
return View(model: returnUrl);
|
|
|
}
|
|
|
|
|
|
#endregion æ<>ƒé™<C3A9>ä¸<C3A4>è¶³
|
|
|
|
|
|
[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")}");
|
|
|
}
|
|
|
|
|
|
#region tools
|
|
|
|
|
|
private void SendCodeToEmail(string email, string code)
|
|
|
{
|
|
|
var name = this._settingService.GetSetting("name").Value;
|
|
|
this._emailSender.SendMail(name,
|
|
|
this._settingService.GetSetting("email:user").Value, email,
|
|
|
$"{name}注册验è¯<C3A8>ç <C3A7>", $"{name} 验è¯<C3A8>ç <C3A7>:{code}",
|
|
|
this._settingService.GetSetting("email:host").Value,
|
|
|
Convert.ToInt32(this._settingService.GetSetting("email:port").Value),
|
|
|
this._settingService.GetSetting("email:user").Value,
|
|
|
this._settingService.GetSetting("email:password").Value);
|
|
|
}
|
|
|
|
|
|
private string GetRandomCode(int length = 4)
|
|
|
{
|
|
|
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 bool RegisterDisabled()
|
|
|
{
|
|
|
return this._cfg.GetValue<bool>("RegisterDisabled");
|
|
|
}
|
|
|
|
|
|
private int GetCaptchaSeconds()
|
|
|
{
|
|
|
return this._cfg.GetValue<int>("CaptchaSeconds");
|
|
|
}
|
|
|
|
|
|
#endregion tools
|
|
|
}
|
|
|
} |