AccountController.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using System;
  2. using System.Diagnostics;
  3. using System.Globalization;
  4. using System.Security.Claims;
  5. using System.Threading.Tasks;
  6. using System.Web.Mvc;
  7. using Abp.Auditing;
  8. using Abp.Configuration.Startup;
  9. using Abp.Domain.Repositories;
  10. using Abp.MultiTenancy;
  11. using Abp.Timing;
  12. using Abp.UI;
  13. using Abp.Web.Models;
  14. using ShwasherSys.Authorization;
  15. using ShwasherSys.Authorization.Users;
  16. using ShwasherSys.Models.Account;
  17. using IwbZero.Auditing;
  18. using IwbZero.Authorization;
  19. using IwbZero.Session;
  20. using IwbZero.Setting;
  21. using Microsoft.AspNet.Identity;
  22. using Microsoft.Owin.Security;
  23. using ShwasherSys.BaseSysInfo;
  24. using Abp.Domain.Uow;
  25. namespace ShwasherSys.Controllers
  26. {
  27. [AllowAnonymous]
  28. [AuditLog("用户账号")]
  29. public class AccountController : ShwasherControllerBase
  30. {
  31. private readonly UserManager _userManager;
  32. private readonly LogInManager _logInManager;
  33. private readonly IMultiTenancyConfig _multiTenancyConfig;
  34. private readonly IAuthenticationManager _authenticationManager;
  35. private readonly IAuditingHelper _auditingHelper;
  36. private readonly IRepository<SysLog,long> _auditLogRepository;
  37. private readonly IAuditInfoProvider _auditInfoProvider;
  38. public AccountController(
  39. UserManager userManager,
  40. LogInManager logInManager,
  41. IMultiTenancyConfig multiTenancyConfig,
  42. IAuthenticationManager authenticationManager,
  43. IIwbSettingManager settingManager, IAuditingHelper auditingHelper, IAuditInfoProvider auditInfoProvider, IRepository<SysLog, long> auditLogRepository)
  44. {
  45. _userManager = userManager;
  46. _logInManager = logInManager;
  47. _multiTenancyConfig = multiTenancyConfig;
  48. _authenticationManager = authenticationManager;
  49. _auditingHelper = auditingHelper;
  50. SettingManager = settingManager;
  51. _auditInfoProvider = auditInfoProvider;
  52. _auditLogRepository = auditLogRepository;
  53. }
  54. #region Login / Logout
  55. [DisableAuditing]
  56. [AuditLog("登陆")]
  57. public async Task<ActionResult> Login(string returnUrl = "", string e = "")
  58. {
  59. if (string.IsNullOrWhiteSpace(returnUrl))
  60. {
  61. returnUrl = Request.ApplicationPath;
  62. }
  63. ViewBag.SystemName = await SettingManager.GetSettingValueAsync(SettingNames.AdminSystemName);
  64. ViewBag.IsMultiTenancyEnabled = _multiTenancyConfig.IsEnabled;
  65. //_authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
  66. //_authenticationManager.SignOut();
  67. var model = new LoginFormViewModel
  68. {
  69. ReturnUrl = returnUrl,
  70. IsMultiTenancyEnabled = false,
  71. IsSelfRegistrationAllowed = false,
  72. MultiTenancySide = MultiTenancySides.Host,
  73. ErrorMsg = e
  74. };
  75. return View(model);
  76. }
  77. [HttpPost]
  78. [UnitOfWork]
  79. [AuditLog("登陆")]
  80. [DisableAuditing]
  81. public async Task<JsonResult> Login(LoginViewModel loginModel, string returnUrl = "", string returnUrlHash = "")
  82. {
  83. CheckModelState();
  84. var actionStopwatch = Stopwatch.StartNew();
  85. var loginResult = await GetLoginResultAsync(
  86. loginModel.UsernameOrEmailAddress,
  87. loginModel.Password
  88. );
  89. await SignInAsync(loginResult.User, loginResult.Identity, loginModel.RememberMe);
  90. //loginModel.Password = "";
  91. //await _auditingHelper.SaveAsync(_auditingHelper.CreateUserLoginAuditInfo(Request, loginResult.User.TenantId, loginResult.User.Id,GetType(),new Dictionary<string, object>(){["loginModel"]= loginModel }));
  92. if (string.IsNullOrWhiteSpace(returnUrl))
  93. {
  94. returnUrl = Request.ApplicationPath;
  95. }
  96. if (!string.IsNullOrWhiteSpace(returnUrlHash))
  97. {
  98. returnUrl = returnUrl + returnUrlHash;
  99. }
  100. actionStopwatch.Stop();
  101. await WriteLoginLog(loginResult, actionStopwatch);
  102. await UnitOfWorkManager.Current.SaveChangesAsync();
  103. return AbpJson(new AjaxResponse { TargetUrl = returnUrl });
  104. }
  105. private async Task<IwbLoginResult<SysUser>> GetLoginResultAsync(string usernameOrEmailAddress, string password)
  106. {
  107. var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password);
  108. if (loginResult.User == null)
  109. {
  110. throw new UserFriendlyException(L("LoginFailed"), "用户名无效,请检查后再登录!");
  111. }
  112. this.LogInfo("用户【" + loginResult.User.UserName + "】登录-" + loginResult.Result);
  113. switch (loginResult.Result)
  114. {
  115. case AbpLoginResultType.Success:
  116. return loginResult;
  117. default:
  118. throw CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress);
  119. }
  120. }
  121. private async Task SignInAsync(SysUser user, ClaimsIdentity identity = null, bool rememberMe = false)
  122. {
  123. if (identity == null)
  124. {
  125. identity = await _userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
  126. }
  127. identity.AddClaim(new Claim(IwbClaimTypes.RememberMe, rememberMe.ToString(CultureInfo.InvariantCulture)));
  128. identity.AddClaim(new Claim(ShwasherConsts.UserDepartmentIdClaimType, user.DepartmentID??""));
  129. //_authenticationManager.SignOut();
  130. _authenticationManager.SignOut(ShwasherConsts.AuthenticationTypes);
  131. // Many browsers do not clean up session cookies when you close them. So the rule of thumb must be:
  132. // For having a consistent behaviour across all browsers, don't rely solely on browser behaviour for proper clean-up
  133. // of session cookies. It is safer to use non-session cookies (IsPersistent == true) in bundle with an expiration date.
  134. // See http://blog.petersondave.com/cookies/Session-Cookies-in-Chrome-Firefox-and-Sitecore/
  135. if (!rememberMe)
  136. {
  137. var expiresUtc = DateTimeOffset.UtcNow.AddMinutes(int.Parse(
  138. System.Configuration.ConfigurationManager.AppSettings[
  139. "AuthSession.ExpireTimeInMinutes"] ?? "90"));
  140. identity.AddClaim(new Claim(IwbClaimTypes.ExpireTime, expiresUtc.ToString(CultureInfo.InvariantCulture)));
  141. }
  142. _authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true }, identity);
  143. }
  144. private UserFriendlyException CreateExceptionForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName = "")
  145. {
  146. switch (result)
  147. {
  148. case AbpLoginResultType.Success:
  149. return new UserFriendlyException("Don't call this method with a success result!");
  150. case AbpLoginResultType.InvalidUserNameOrEmailAddress:
  151. case AbpLoginResultType.InvalidPassword:
  152. return new UserFriendlyException(L("LoginFailed"), L("InvalidUserNameOrPassword"));
  153. case AbpLoginResultType.InvalidTenancyName:
  154. return new UserFriendlyException(L("LoginFailed"), L("ThereIsNoTenantDefinedWithName{0}", tenancyName));
  155. case AbpLoginResultType.TenantIsNotActive:
  156. return new UserFriendlyException(L("LoginFailed"), L("TenantIsNotActive", tenancyName));
  157. case AbpLoginResultType.UserIsNotActive:
  158. return new UserFriendlyException(L("LoginFailed"), L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress));
  159. case AbpLoginResultType.UserEmailIsNotConfirmed:
  160. return new UserFriendlyException(L("LoginFailed"), "UserEmailIsNotConfirmedAndCanNotLogin");
  161. case AbpLoginResultType.LockedOut:
  162. return new UserFriendlyException(L("LoginFailed"), L("UserLockedOutMessage"));
  163. default: //Can not fall to default actually. But other result types can be added in the future and we may forget to handle it
  164. Logger.Warn("Unhandled login fail reason: " + result);
  165. return new UserFriendlyException(L("LoginFailed"));
  166. }
  167. }
  168. private async Task WriteLoginLog(IwbLoginResult<SysUser> loginResult, Stopwatch actionStopwatch)
  169. {
  170. try
  171. {
  172. var auditInfo = new AuditInfo
  173. {
  174. TenantId = null,
  175. UserId = loginResult.User.Id,
  176. ImpersonatorUserId = AbpSession.ImpersonatorUserId,
  177. ImpersonatorTenantId = AbpSession.ImpersonatorTenantId,
  178. ServiceName = "用户账号",
  179. MethodName = "登陆",
  180. Parameters = "",
  181. ExecutionTime = Clock.Now,
  182. ExecutionDuration = Convert.ToInt32(actionStopwatch.Elapsed.TotalMilliseconds)
  183. };
  184. _auditInfoProvider.Fill(auditInfo);
  185. //await _auditingHelper.SaveAsync(auditInfo);
  186. await _auditLogRepository.InsertAsync(SysLog.CreateFromAuditInfo(auditInfo, loginResult.User.UserName, 1));
  187. }
  188. catch (Exception e)
  189. {
  190. this.LogError(e);
  191. }
  192. }
  193. [AuditLog("注销")]
  194. public ActionResult Logout()
  195. {
  196. _authenticationManager.SignOut();
  197. return RedirectToAction("Login");
  198. }
  199. [AuditLog("修改密码")]
  200. public async Task<JsonResult> UpdatePassword(UpdatePwdViewModel input)
  201. {
  202. CheckModelState();
  203. var loginResult = await GetUpdatePwdResultAsync(
  204. input.LoginName,
  205. input.LoginPassword
  206. );
  207. if (loginResult.Result == AbpLoginResultType.Success)
  208. {
  209. await _userManager.ChangePasswordAsync(loginResult.User, input.NewPassword);
  210. await CurrentUnitOfWork.SaveChangesAsync();
  211. }
  212. return AbpJson(new AjaxResponse { Success = true });
  213. }
  214. private async Task<IwbLoginResult<SysUser>> GetUpdatePwdResultAsync(string usernameOrEmailAddress, string password)
  215. {
  216. var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, false, true);
  217. this.LogInfo("用户【" + loginResult.User.UserName + "】修改密码-" + loginResult.Result);
  218. switch (loginResult.Result)
  219. {
  220. case AbpLoginResultType.Success:
  221. return loginResult;
  222. default:
  223. throw CreateExceptionForFailedUpdatePwdAttempt(loginResult.Result, usernameOrEmailAddress);
  224. }
  225. }
  226. private Exception CreateExceptionForFailedUpdatePwdAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName = "")
  227. {
  228. switch (result)
  229. {
  230. case AbpLoginResultType.Success:
  231. return new ApplicationException("Don't call this method with a success result!");
  232. case AbpLoginResultType.InvalidUserNameOrEmailAddress:
  233. case AbpLoginResultType.InvalidPassword:
  234. return new UserFriendlyException("密码修改失败", L("InvalidUserNameOrPassword"));
  235. case AbpLoginResultType.InvalidTenancyName:
  236. return new UserFriendlyException("密码修改失败", L("ThereIsNoTenantDefinedWithName{0}", tenancyName));
  237. case AbpLoginResultType.TenantIsNotActive:
  238. return new UserFriendlyException("密码修改失败", L("TenantIsNotActive", tenancyName));
  239. case AbpLoginResultType.UserIsNotActive:
  240. return new UserFriendlyException("密码修改失败", L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress));
  241. case AbpLoginResultType.UserEmailIsNotConfirmed:
  242. return new UserFriendlyException("密码修改失败", "UserEmailIsNotConfirmedAndCanNotLogin");
  243. case AbpLoginResultType.LockedOut:
  244. return new UserFriendlyException("密码修改失败", L("UserLockedOutMessage"));
  245. default: //Can not fall to default actually. But other result types can be added in the future and we may forget to handle it
  246. Logger.Warn("Unhandled login fail reason: " + result);
  247. return new UserFriendlyException("密码修改失败");
  248. }
  249. }
  250. #endregion
  251. }
  252. }