PassportController.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. using CacheManager.Core;
  2. using Hangfire;
  3. using Masuit.MyBlogs.Core.Common;
  4. using Masuit.MyBlogs.Core.Configs;
  5. using Masuit.MyBlogs.Core.Extensions.Firewall;
  6. using Masuit.MyBlogs.Core.Extensions.Hangfire;
  7. using Masuit.MyBlogs.Core.Infrastructure.Services.Interface;
  8. using Masuit.MyBlogs.Core.Models.DTO;
  9. using Masuit.MyBlogs.Core.Models.Enum;
  10. using Masuit.MyBlogs.Core.Models.ViewModel;
  11. using Masuit.Tools;
  12. using Masuit.Tools.AspNetCore.Mime;
  13. using Masuit.Tools.AspNetCore.ResumeFileResults.Extensions;
  14. using Masuit.Tools.Core.Net;
  15. using Masuit.Tools.Logging;
  16. using Masuit.Tools.Security;
  17. using Masuit.Tools.Strings;
  18. using Microsoft.AspNetCore.Mvc;
  19. using System.Net;
  20. using System.Web;
  21. namespace Masuit.MyBlogs.Core.Controllers
  22. {
  23. /// <summary>
  24. /// 登录授权
  25. /// </summary>
  26. [ApiExplorerSettings(IgnoreApi = true), ServiceFilter(typeof(FirewallAttribute))]
  27. public class PassportController : Controller
  28. {
  29. /// <summary>
  30. /// 用户
  31. /// </summary>
  32. public IUserInfoService UserInfoService { get; set; }
  33. public IFirewallRepoter FirewallRepoter { get; set; }
  34. /// <summary>
  35. /// 客户端的真实IP
  36. /// </summary>
  37. public string ClientIP => HttpContext.Connection.RemoteIpAddress.ToString();
  38. /// <summary>
  39. ///
  40. /// </summary>
  41. /// <param name="data"></param>
  42. /// <param name="isTrue"></param>
  43. /// <param name="message"></param>
  44. /// <returns></returns>
  45. public ActionResult ResultData(object data, bool isTrue = true, string message = "")
  46. {
  47. return Json(new
  48. {
  49. Success = isTrue,
  50. Message = message,
  51. Data = data
  52. });
  53. }
  54. /// <summary>
  55. /// 登录页
  56. /// </summary>
  57. /// <returns></returns>
  58. public ActionResult Login()
  59. {
  60. var keys = RsaCrypt.GenerateRsaKeys(RsaKeyType.PKCS1);
  61. Response.Cookies.Append(nameof(keys.PublicKey), keys.PublicKey, new CookieOptions()
  62. {
  63. SameSite = SameSiteMode.Lax
  64. });
  65. HttpContext.Session.Set(nameof(keys.PrivateKey), keys.PrivateKey);
  66. string from = Request.Query["from"];
  67. if (!string.IsNullOrEmpty(from))
  68. {
  69. from = HttpUtility.UrlDecode(from);
  70. Response.Cookies.Append("refer", from, new CookieOptions()
  71. {
  72. SameSite = SameSiteMode.Lax
  73. });
  74. }
  75. if (HttpContext.Session.Get<UserInfoDto>(SessionKey.UserInfo) != null)
  76. {
  77. if (string.IsNullOrEmpty(from))
  78. {
  79. return RedirectToAction("Index", "Home");
  80. }
  81. return LocalRedirect(from);
  82. }
  83. if (Request.Cookies.Count > 2)
  84. {
  85. string name = Request.Cookies["username"];
  86. string pwd = Request.Cookies["password"]?.DesDecrypt(AppConfig.BaiduAK);
  87. var userInfo = UserInfoService.Login(name, pwd);
  88. if (userInfo != null)
  89. {
  90. Response.Cookies.Append("username", name, new CookieOptions()
  91. {
  92. Expires = DateTime.Now.AddYears(1),
  93. SameSite = SameSiteMode.Lax
  94. });
  95. Response.Cookies.Append("password", Request.Cookies["password"], new CookieOptions()
  96. {
  97. Expires = DateTime.Now.AddYears(1),
  98. SameSite = SameSiteMode.Lax
  99. });
  100. HttpContext.Session.Set(SessionKey.UserInfo, userInfo);
  101. BackgroundJob.Enqueue<IHangfireBackJob>(job => job.LoginRecord(userInfo, ClientIP, LoginType.Default));
  102. if (string.IsNullOrEmpty(from))
  103. {
  104. return RedirectToAction("Index", "Home");
  105. }
  106. return LocalRedirect(from);
  107. }
  108. }
  109. return View();
  110. }
  111. /// <summary>
  112. /// 登陆检查
  113. /// </summary>
  114. /// <param name="username"></param>
  115. /// <param name="password"></param>
  116. /// <param name="valid"></param>
  117. /// <param name="remem"></param>
  118. /// <returns></returns>
  119. [HttpPost, ValidateAntiForgeryToken]
  120. public ActionResult Login([FromServices] ICacheManager<int> cacheManager, string username, string password, string valid, string remem)
  121. {
  122. string validSession = HttpContext.Session.Get<string>("valid") ?? string.Empty; //将验证码从Session中取出来,用于登录验证比较
  123. if (string.IsNullOrEmpty(validSession) || !valid.Trim().Equals(validSession, StringComparison.InvariantCultureIgnoreCase))
  124. {
  125. return ResultData(null, false, "验证码错误");
  126. }
  127. HttpContext.Session.Remove("valid"); //验证成功就销毁验证码Session,非常重要
  128. if (string.IsNullOrEmpty(username.Trim()) || string.IsNullOrEmpty(password.Trim()))
  129. {
  130. return ResultData(null, false, "用户名或密码不能为空");
  131. }
  132. try
  133. {
  134. var privateKey = HttpContext.Session.Get<string>(nameof(RsaKey.PrivateKey));
  135. password = password.RSADecrypt(privateKey);
  136. }
  137. catch (Exception)
  138. {
  139. LogManager.Info("登录失败,私钥:" + HttpContext.Session.Get<string>(nameof(RsaKey.PrivateKey)));
  140. throw;
  141. }
  142. var userInfo = UserInfoService.Login(username, password);
  143. if (userInfo == null)
  144. {
  145. var times = cacheManager.AddOrUpdate("LoginError:" + ClientIP, 1, i => i + 1, 5);
  146. if (times > 30)
  147. {
  148. FirewallRepoter.ReportAsync(IPAddress.Parse(ClientIP)).ContinueWith(_ => LogManager.Info($"多次登录用户名或密码错误,疑似爆破行为,已上报IP{ClientIP}至:" + FirewallRepoter.ReporterName));
  149. }
  150. return ResultData(null, false, "用户名或密码错误");
  151. }
  152. HttpContext.Session.Set(SessionKey.UserInfo, userInfo);
  153. if (remem.Trim().Contains(new[] { "on", "true" })) //是否记住登录
  154. {
  155. Response.Cookies.Append("username", HttpUtility.UrlEncode(username.Trim()), new CookieOptions()
  156. {
  157. Expires = DateTime.Now.AddYears(1),
  158. SameSite = SameSiteMode.Lax
  159. });
  160. Response.Cookies.Append("password", password.Trim().DesEncrypt(AppConfig.BaiduAK), new CookieOptions()
  161. {
  162. Expires = DateTime.Now.AddYears(1),
  163. SameSite = SameSiteMode.Lax
  164. });
  165. }
  166. BackgroundJob.Enqueue<IHangfireBackJob>(job => job.LoginRecord(userInfo, ClientIP, LoginType.Default));
  167. string refer = Request.Cookies["refer"];
  168. Response.Cookies.Delete(nameof(RsaKey.PublicKey), new CookieOptions()
  169. {
  170. SameSite = SameSiteMode.Lax
  171. });
  172. Response.Cookies.Delete("refer", new CookieOptions()
  173. {
  174. SameSite = SameSiteMode.Lax
  175. });
  176. HttpContext.Session.Remove(nameof(RsaKey.PrivateKey));
  177. return ResultData(null, true, string.IsNullOrEmpty(refer) ? "/" : refer);
  178. }
  179. /// <summary>
  180. /// 生成验证码
  181. /// </summary>
  182. /// <returns></returns>
  183. public ActionResult ValidateCode()
  184. {
  185. string code = Tools.Strings.ValidateCode.CreateValidateCode(6);
  186. HttpContext.Session.Set("valid", code); //将验证码生成到Session中
  187. var buffer = HttpContext.CreateValidateGraphic(code);
  188. return this.ResumeFile(buffer, ContentType.Jpeg, "验证码.jpg");
  189. }
  190. /// <summary>
  191. /// 检查验证码
  192. /// </summary>
  193. /// <param name="code"></param>
  194. /// <returns></returns>
  195. [HttpPost]
  196. public ActionResult CheckValidateCode(string code)
  197. {
  198. string validSession = HttpContext.Session.Get<string>("valid");
  199. if (string.IsNullOrEmpty(validSession) || !code.Trim().Equals(validSession, StringComparison.InvariantCultureIgnoreCase))
  200. {
  201. return ResultData(null, false, "验证码错误");
  202. }
  203. return ResultData(null, false, "验证码正确");
  204. }
  205. /// <summary>
  206. /// 获取用户信息
  207. /// </summary>
  208. /// <returns></returns>
  209. public ActionResult GetUserInfo()
  210. {
  211. var user = HttpContext.Session.Get<UserInfoDto>(SessionKey.UserInfo);
  212. #if DEBUG
  213. user = UserInfoService.GetByUsername("masuit").Mapper<UserInfoDto>();
  214. #endif
  215. return ResultData(user);
  216. }
  217. /// <summary>
  218. /// 注销登录
  219. /// </summary>
  220. /// <returns></returns>
  221. public ActionResult Logout()
  222. {
  223. HttpContext.Session.Remove(SessionKey.UserInfo);
  224. Response.Cookies.Delete("username", new CookieOptions()
  225. {
  226. SameSite = SameSiteMode.Lax
  227. });
  228. Response.Cookies.Delete("password", new CookieOptions()
  229. {
  230. SameSite = SameSiteMode.Lax
  231. });
  232. HttpContext.Session.Clear();
  233. return Request.Method.Equals(HttpMethods.Get) ? RedirectToAction("Index", "Home") : ResultData(null, message: "注销成功!");
  234. }
  235. }
  236. }