mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-08-25 03:58:28 +08:00
150 lines
5.9 KiB
C#
150 lines
5.9 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using JetBrains.Annotations;
|
|
using Orchard.Logging;
|
|
using Orchard.ContentManagement;
|
|
using Orchard.Users.Models;
|
|
using Orchard.Security;
|
|
using System.Xml.Linq;
|
|
using Orchard.Services;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using Orchard.Messaging.Services;
|
|
using Orchard.Environment.Configuration;
|
|
|
|
namespace Orchard.Users.Services {
|
|
[UsedImplicitly]
|
|
public class UserService : IUserService {
|
|
private static readonly TimeSpan DelayToValidate = new TimeSpan(7, 0, 0, 0); // one week to validate email
|
|
private static readonly TimeSpan DelayToResetPassword = new TimeSpan(1, 0, 0, 0); // 24 hours to validate email
|
|
|
|
private readonly IContentManager _contentManager;
|
|
private readonly IMembershipService _membershipService;
|
|
private readonly IClock _clock;
|
|
private readonly IMessageManager _messageManager;
|
|
private readonly IEncryptionService _encryptionService;
|
|
|
|
public UserService(IContentManager contentManager, IMembershipService membershipService, IClock clock, IMessageManager messageManager, ShellSettings shellSettings, IEncryptionService encryptionService) {
|
|
_contentManager = contentManager;
|
|
_membershipService = membershipService;
|
|
_clock = clock;
|
|
_messageManager = messageManager;
|
|
_encryptionService = encryptionService;
|
|
Logger = NullLogger.Instance;
|
|
}
|
|
|
|
public ILogger Logger { get; set; }
|
|
|
|
public bool VerifyUserUnicity(string userName, string email) {
|
|
string normalizedUserName = userName.ToLowerInvariant();
|
|
|
|
if (_contentManager.Query<UserPart, UserPartRecord>()
|
|
.Where(user =>
|
|
user.NormalizedUserName == normalizedUserName ||
|
|
user.Email == email)
|
|
.List().Any()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool VerifyUserUnicity(int id, string userName, string email) {
|
|
string normalizedUserName = userName.ToLowerInvariant();
|
|
|
|
if (_contentManager.Query<UserPart, UserPartRecord>()
|
|
.Where(user =>
|
|
user.NormalizedUserName == normalizedUserName ||
|
|
user.Email == email)
|
|
.List().Any(user => user.Id != id)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public string CreateNonce(IUser user, TimeSpan delay) {
|
|
var challengeToken = new XElement("n", new XAttribute("un", user.UserName), new XAttribute("utc", _clock.UtcNow.ToUniversalTime().Add(delay).ToString(CultureInfo.InvariantCulture))).ToString();
|
|
var data = Encoding.UTF8.GetBytes(challengeToken);
|
|
return Convert.ToBase64String(_encryptionService.Encode(data));
|
|
}
|
|
|
|
public bool DecryptNonce(string nonce, out string username, out DateTime validateByUtc) {
|
|
username = null;
|
|
validateByUtc = _clock.UtcNow;
|
|
|
|
try {
|
|
var data = _encryptionService.Decode(Convert.FromBase64String(nonce));
|
|
var xml = Encoding.UTF8.GetString(data);
|
|
var element = XElement.Parse(xml);
|
|
username = element.Attribute("un").Value;
|
|
validateByUtc = DateTime.Parse(element.Attribute("utc").Value, CultureInfo.InvariantCulture);
|
|
return _clock.UtcNow <= validateByUtc;
|
|
}
|
|
catch {
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public IUser ValidateChallenge(string nonce) {
|
|
string username;
|
|
DateTime validateByUtc;
|
|
|
|
if (!DecryptNonce(nonce, out username, out validateByUtc)) {
|
|
return null;
|
|
}
|
|
|
|
if (validateByUtc < _clock.UtcNow)
|
|
return null;
|
|
|
|
var user = _membershipService.GetUser(username);
|
|
if (user == null)
|
|
return null;
|
|
|
|
user.As<UserPart>().EmailStatus = UserStatus.Approved;
|
|
|
|
return user;
|
|
}
|
|
|
|
public void SendChallengeEmail(IUser user, Func<string, string> createUrl) {
|
|
string nonce = CreateNonce(user, DelayToValidate);
|
|
string url = createUrl(nonce);
|
|
_messageManager.Send(user.ContentItem.Record, MessageTypes.Validation, "email", new Dictionary<string, string> { { "ChallengeUrl", url } });
|
|
}
|
|
|
|
public bool SendLostPasswordEmail(string usernameOrEmail, Func<string, string> createUrl) {
|
|
var lowerName = usernameOrEmail.ToLowerInvariant();
|
|
var user = _contentManager.Query<UserPart, UserPartRecord>().Where(u => u.NormalizedUserName == lowerName || u.Email == lowerName).List().FirstOrDefault();
|
|
|
|
if (user != null) {
|
|
string nonce = CreateNonce(user, DelayToResetPassword);
|
|
string url = createUrl(nonce);
|
|
|
|
_messageManager.Send(user.ContentItem.Record, MessageTypes.LostPassword, "email", new Dictionary<string, string> { { "LostPasswordUrl", url } });
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public IUser ValidateLostPassword(string nonce) {
|
|
string username;
|
|
DateTime validateByUtc;
|
|
|
|
if (!DecryptNonce(nonce, out username, out validateByUtc)) {
|
|
return null;
|
|
}
|
|
|
|
if (validateByUtc < _clock.UtcNow)
|
|
return null;
|
|
|
|
var user = _membershipService.GetUser(username);
|
|
if (user == null)
|
|
return null;
|
|
|
|
return user;
|
|
}
|
|
}
|
|
} |