using System.ComponentModel.DataAnnotations;
using Dpz.Core.Authenticator;
using Dpz.Core.EnumLibrary;
using Dpz.Core.Public.ViewModel.Request;
using Dpz.Core.Service.ObjectStorage.Services;
using Dpz.Core.Service.V4.Services;
using Dpz.Core.Web.Models;
using MongoDB.Bson;
using IMumbleService = Dpz.Core.Service.V4.Services.IMumbleService;
namespace Dpz.Core.Web.Controllers;
public class AccountController(
IApplicationSignInManager signInManager,
IArticleService articleService,
IMusicService musicService,
IMumbleService mumbleService,
IAccountService accountService,
IObjectStorageOperation objectStorageService,
ILogger<AccountController> logger)
: Controller
{
[HttpPost]
public async Task<IActionResult> LogOut()
{
await HttpContext.SignOutAsync(Program.AuthorizeCookieName);
return Redirect("/");
}
[ValidateAntiForgeryToken]
[HttpPost]
public async Task<IActionResult> Login(
[FromServices] IAppOptionService appService,
[FromServices] IUserTwoFactorService userTwoFactorService,
[Required]string account,
[Required]string password,
string? pinCode = null,
string fromUrl = "/",
bool remember = false)
{
if (await appService.IsAccountLockAsync(account))
{
TempData["Msg"] = "短时间内多次登录失败,账户已被锁定24小时!";
return RedirectToAction("Login", "Home", new { fromUrl });
}
#region 双因素验证
var (key, isBind) = await userTwoFactorService.GetKeyAsync(account);
if (isBind)
{
if (string.IsNullOrEmpty(pinCode))
{
TempData["Msg"] = "请输入PIN码";
return RedirectToAction("Login", "Home", new { fromUrl });
}
var twoFactorAuthenticator = new TwoFactorAuthenticator();
var keyBuffer = Encoding.UTF8.GetBytes(key);
var keyBase32 = Base32Encoding.ToString(keyBuffer);
var twoFactorResult = twoFactorAuthenticator.ValidateTwoFactorPIN(keyBase32, pinCode, true);
if (!twoFactorResult)
{
TempData["Msg"] = "PIN码验证失败";
return RedirectToAction("Login", "Home", new { fromUrl });
}
}
#endregion
var result = await signInManager.PasswordSignInAsync(account, password, remember, false);
if (result.Succeeded)
{
await appService.LoginSuccessfulAsync(account);
if (Url.IsLocalUrl(fromUrl))
{
if (!isBind)
{
return RedirectToAction("BindTwoFactor", "Home", new { fromUrl });
}
return Redirect(fromUrl);
}
if (!isBind)
{
return RedirectToAction("BindTwoFactor", "Home", new { fromUrl = "/" });
}
return Redirect("/");
}
await appService.LoginFailAsync(account);
TempData["Msg"] = "用户名或密码错误!";
return RedirectToAction("Login", "Home", new { fromUrl });
}
/// <summary>
/// 身份认证
/// </summary>
/// <returns></returns>
[HttpPost("{platform}/auth")]
public async Task<IActionResult> Auth(
[FromServices] IAppOptionService appService,
[FromServices] IUserTwoFactorService userTwoFactorService,
[FromServices] IAuthenticateService authenticateService,
TokenPlatform platform,
string account,
string password,
string? pinCode = null)
{
if (await appService.IsAccountLockAsync(account))
{
return BadRequest("短时间内多次登录失败,账户已被锁定24小时!");
}
#region 双因素验证
var (key, isBind) = await userTwoFactorService.GetKeyAsync(account);
if (isBind)
{
if (string.IsNullOrEmpty(pinCode))
{
return BadRequest("PIN码为空!");
}
var twoFactorAuthenticator = new TwoFactorAuthenticator();
var keyBuffer = Encoding.UTF8.GetBytes(key);
var keyBase32 = Base32Encoding.ToString(keyBuffer);
var twoFactorResult = twoFactorAuthenticator.ValidateTwoFactorPIN(keyBase32, pinCode, true);
if (!twoFactorResult)
{
return BadRequest("PIN码验证错误!");
}
}
#endregion
var authRequest = new AuthenticateRequest
{
Account = account,
IpAddress = Request.Headers.UserAgent,
Password = password,
Platform = platform,
UserAgent = Request.Headers.UserAgent
};
var result = await authenticateService.AuthenticatedAsync(authRequest);
if (result is null)
{
await appService.LoginFailAsync(account);
return BadRequest("账号或密码错误!");
}
await appService.LoginSuccessfulAsync(account);
return Ok(result);
}
[CheckAuthorize, HttpPost]
public async Task<IActionResult> UpdateSign(string sign)
{
var userInfo = this.GetIdentity();
if (userInfo == null)
{
return Json(new ResultInfo(false));
}
await accountService.UpdateSignAsync(userInfo.Id, sign);
return Json(new ResultInfo(true));
}
[CheckAuthorize, HttpPost]
public async Task<IActionResult> UpdateInfo(string name, Sex sex, string? sign = null)
{
if (string.IsNullOrEmpty(name))
{
return Json(new ResultInfo("昵称不能为空"));
}
var userInfo = this.GetIdentity();
if (userInfo == null)
{
return Json(new ResultInfo(false));
}
await accountService.UpdateInfoAsync(userInfo.Id, name, sign, sex);
var newUserInfo = await accountService.GetOneUserAsync(userInfo.Id);
await signInManager.RefreshSignInAsync(newUserInfo);
return Json(new ResultInfo(true));
}
[CheckAuthorize, HttpPost]
public async Task<IActionResult> UpdateAvatar(IFormFile? avatar)
{
if (avatar == null || avatar.Length <= 0 || !avatar.ContentType.Contains("image"))
{
return Json(new ResultInfo("请上传头像"));
}
var userInfo = this.GetIdentity();
if (userInfo == null)
{
return Json(new ResultInfo(false));
}
var fileName = ObjectId.GenerateNewId() + avatar.FileName[avatar.FileName.LastIndexOf('.')..];
var path = new[] { "images", "avatar" };
var result = await objectStorageService.UploadAsync(avatar.OpenReadStream(), path, fileName);
await accountService.UpdateAvatarAsync(userInfo.Id, result.AccessUrl);
var newUserInfo = await accountService.GetOneUserAsync(userInfo.Id);
await signInManager.RefreshSignInAsync(newUserInfo);
return Json(new ResultInfo(data: result.AccessUrl));
}
[CheckAuthorize, HttpPost]
public async Task<ActionResult> ChangePassword(string nowpass = "", string pass = "", string repass = "")
{
if (string.IsNullOrEmpty(nowpass) || string.IsNullOrEmpty(pass) || string.IsNullOrEmpty(repass))
return Json(new ResultInfo("密码不能为空哦!"));
if (pass != repass) return Json(new ResultInfo("两次密码输入不一致!"));
var userInfo = this.GetIdentity();
if (userInfo == null)
{
return Json(new ResultInfo(false));
}
var msg = await accountService.ChangPwdAsync(userInfo.Id, nowpass, repass);
logger.LogInformation("{Msg}", string.IsNullOrEmpty(msg) ? "修改密码" : msg);
return Json(new ResultInfo(msg, msg == ""));
}
[CheckAuthorize]
public async Task<IActionResult> Index()
{
return await Task.Factory.StartNew(() =>
{
var userInfo = this.GetIdentity();
if (userInfo == null)
{
return (IActionResult)RedirectToAction("Login", "Home", new { fromUrl = Url.Action("Index","Account") });
}
this.SetTitle(userInfo.Name + "个人信息");
ViewBag.AccountMenu = AccountMenu.Setting;
return View(userInfo);
});
}
[Route("re-login.html")]
public async Task<IActionResult> ReLogin()
{
await HttpContext.SignOutAsync(Program.AuthorizeCookieName);
return View();
}
[CheckAuthorize]
public async Task<IActionResult> MyArticle(
int cPage = 1,
int pSize = 20,
string tag = "",
string title = "")
{
if (Request.IsAjax())
{
var userInfo = User.GetIdentity();
var source = await articleService.GetPagesAsync(cPage, pSize, title, userInfo.Id, tag);
return Json(source.ToGridManagerSource());
}
ViewBag.AccountMenu = AccountMenu.Article;
this.SetTitle("我的文章");
var tags = await articleService.GetAllTagsAsync();
return View(tags);
}
[CheckAuthorize]
public async Task<IActionResult> MyTalk(int cPage = 1, int pSize = 20, string content = "")
{
if (Request.IsAjax())
{
var userInfo = User.GetIdentity();
var source = await mumbleService.GetPagesAsync(cPage, pSize, content, userInfo.Id);
return Json(source.ToGridManagerSource());
}
ViewBag.AccountMenu = AccountMenu.Talk;
this.SetTitle("我的碎碎念");
return View();
}
[CheckAuthorize]
public async Task<IActionResult> MyTimeline([FromServices] ITimelineService timelineService, int cPage = 1,
int pSize = 20, string content = "")
{
if (Request.IsAjax())
{
var userInfo = User.GetIdentity();
var source = await timelineService.GetPageAsync(cPage, pSize, content, userInfo.Id);
return Json(source.ToGridManagerSource());
}
ViewBag.AccountMenu = AccountMenu.Timeline;
this.SetTitle("我的时间轴");
return View();
}
[CheckAuthorize, HttpGet]
public async Task<IActionResult> MusicLibrary(int cPage = 1, int pSize = 20, string title = "")
{
if (Request.IsAjax())
{
var list = await musicService.GetPagesAsync(cPage, pSize, title);
return Json(list.ToGridManagerSource());
}
this.SetTitle("站点曲库");
ViewBag.AccountMenu = AccountMenu.MusicLibrary;
return View();
}
public async Task<IActionResult> GetUserInfo(
#if DEBUG
[FromServices]IOptions<TokenManagement> tokenManagement
#endif
)
{
return await Task.Factory.StartNew(() =>
{
#if DEBUG
var user = HttpContext.GetIdentity(tokenManagement.Value);
#else
var user = User.GetIdentity();
#endif
if (user == null)
return Json(new ResultInfo(false));
return Json(new ResultInfo(user));
});
}
#if DEBUG
public IActionResult Index2()
{
return View();
}
#endif
}