[Common]
继续完善RT登录逻辑。 已在SicManual中测试,以前的登录逻辑没有问题,新的踢出逻辑还未测试。 [UI.Client] 移除未使用的登录控件。
This commit is contained in:
parent
45bb9e7bf7
commit
56bbd2e440
|
@ -152,87 +152,6 @@ namespace Aitex.Core.Account
|
|||
GetAccountList();
|
||||
}
|
||||
|
||||
public LoginResult Login(string accountId, string accountPwd)
|
||||
{
|
||||
try
|
||||
{
|
||||
LOG.Write($"用户{accountId}尝试登录系统");
|
||||
accountId = accountId.ToLower();
|
||||
var loginResult = new LoginResult();
|
||||
if (accountId == "su" && accountPwd == "su")
|
||||
{
|
||||
loginResult.ActSucc = true;
|
||||
loginResult.AccountInfo = GetAccountInfo("admin").AccountInfo;
|
||||
loginResult.Token = Guid.NewGuid().ToString();
|
||||
}
|
||||
else if (!FileSigner.IsValid(_accountPath))
|
||||
{
|
||||
loginResult.Description = "File signer corrupt";
|
||||
loginResult.ActSucc = false;
|
||||
}
|
||||
else if (_userList.ContainsKey(accountId))
|
||||
{
|
||||
var accountInfo = GetAccountInfo(accountId).AccountInfo;
|
||||
if (accountInfo.Md5Pwd == Md5Helper.GetMd5Hash(accountPwd))
|
||||
{
|
||||
loginResult.ActSucc = true;
|
||||
loginResult.Description = $"{accountId} login succeed";
|
||||
loginResult.AccountInfo = accountInfo;
|
||||
loginResult.Token = Guid.NewGuid().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
loginResult.ActSucc = false;
|
||||
loginResult.Description = $"account {accountId} already login";
|
||||
}
|
||||
}
|
||||
else if (_userList.Count >= 16 && accountId != "admin")
|
||||
{
|
||||
loginResult.ActSucc = false;
|
||||
loginResult.Description = $"more than {16} users login";
|
||||
}
|
||||
else
|
||||
{
|
||||
var accountInfo2 = GetAccountInfo(accountId).AccountInfo;
|
||||
if (accountInfo2 == null)
|
||||
{
|
||||
loginResult.ActSucc = false;
|
||||
loginResult.Description = $"{accountId} not exist";
|
||||
}
|
||||
else if (accountInfo2.Md5Pwd != Md5Helper.GetMd5Hash(accountPwd) && (accountInfo2.Role != "Admin" || accountPwd != Md5Helper.GenerateDynamicPassword(SerialNumber)))
|
||||
{
|
||||
loginResult.ActSucc = false;
|
||||
loginResult.Description = $"password error";
|
||||
}
|
||||
else if (!accountInfo2.AccountStatus)
|
||||
{
|
||||
loginResult.ActSucc = false;
|
||||
loginResult.Description = $"account {accountId} is disabled";
|
||||
}
|
||||
else
|
||||
{
|
||||
_userList.Add(accountId, new Tuple<Guid, DateTime, string>(NotificationService.ClientGuid, DateTime.Now, NotificationService.ClientHostName));
|
||||
loginResult.ActSucc = true;
|
||||
loginResult.Description = $"{accountId} login succeed";
|
||||
loginResult.AccountInfo = accountInfo2;
|
||||
loginResult.Token = Guid.NewGuid().ToString();
|
||||
EV.PostMessage(Module, EventEnum.UserLoggedIn, accountId);
|
||||
}
|
||||
}
|
||||
return loginResult;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var text = string.Format("account system inner exception", accountId);
|
||||
LOG.Write(ex, text);
|
||||
return new LoginResult
|
||||
{
|
||||
ActSucc = false,
|
||||
Description = text
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void Logout(string accountId)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -16,21 +16,7 @@ namespace Aitex.Core.Account
|
|||
public sealed class AccountService : IAccountService
|
||||
{
|
||||
public string Module => "System";
|
||||
|
||||
public LoginResult Login(string accountId, string accountPwd)
|
||||
{
|
||||
if (Singleton<KeyManager>.Instance.IsExpired)
|
||||
{
|
||||
EV.PostMessage("System", EventEnum.DefaultWarning, "Software is expired. Can not login");
|
||||
return new LoginResult
|
||||
{
|
||||
ActSucc = false,
|
||||
Description = "Software is expired"
|
||||
};
|
||||
}
|
||||
EV.PostInfoLog(Module, $"User {accountId} try to login System.");
|
||||
return AccountManager.Instance.Login(accountId, accountPwd);
|
||||
}
|
||||
|
||||
|
||||
public void Logout(string accountId)
|
||||
{
|
||||
|
@ -246,10 +232,10 @@ namespace Aitex.Core.Account
|
|||
return AccountExManager.Instance.RoleLoader.DeleteAccount(loginName);
|
||||
}
|
||||
|
||||
public async Task<LoginRequestResults> LoginEx(string userName, string password, string role,
|
||||
public async Task<LoginResult> LoginEx(string userName, string password, string role,
|
||||
LoginClientInfo clientInfo)
|
||||
{
|
||||
return await AccountExManager.Instance.RequestLogin(userName, password, role, clientInfo);
|
||||
return await AccountExManager.Instance.Login(userName, password, role, clientInfo);
|
||||
}
|
||||
|
||||
public void CancelLoginRequest(string userName)
|
||||
|
@ -257,9 +243,20 @@ namespace Aitex.Core.Account
|
|||
AccountExManager.Instance.CancelLoginRequest(userName);
|
||||
}
|
||||
|
||||
public void LogoutEx(string sessionId)
|
||||
public void ConfirmLoginRequest(Credential requestingCred)
|
||||
{
|
||||
AccountExManager.Instance.Logout(sessionId);
|
||||
AccountExManager.Instance.ConfirmedLoginRequest(requestingCred);
|
||||
}
|
||||
|
||||
public void RejectLoginRequest(Credential requestingCred)
|
||||
{
|
||||
AccountExManager.Instance.RejectLoginRequest(requestingCred);
|
||||
}
|
||||
|
||||
|
||||
public void LogoutEx(Guid token)
|
||||
{
|
||||
AccountExManager.Instance.Logout(token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -267,7 +264,7 @@ namespace Aitex.Core.Account
|
|||
/// </summary>
|
||||
/// <param name="token">客户端登录凭据令牌。</param>
|
||||
/// <returns></returns>
|
||||
public CredentialKeepAliveResults KeepAlive(string token)
|
||||
public CredentialKeepAliveResults KeepAlive(Guid token)
|
||||
{
|
||||
return CredentialManager.Instance.KeepAlive(token);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using MECF.Framework.Common.Account.Extends;
|
||||
|
||||
namespace Aitex.Core.Account;
|
||||
|
@ -24,7 +25,11 @@ public class Credential
|
|||
/// </remarks>
|
||||
public Credential()
|
||||
{
|
||||
|
||||
Token = Guid.Empty;
|
||||
State = CredentialState.Requesting;
|
||||
LoginTime = DateTime.MinValue;
|
||||
LastAliveTime = DateTime.Now;
|
||||
LoginRequestCancellationTokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -32,7 +37,7 @@ public class Credential
|
|||
/// </summary>
|
||||
/// <param name="token">登录令牌。</param>
|
||||
/// <param name="accountInfo">登录账户信息。</param>
|
||||
public Credential(string token, AccountEx accountInfo)
|
||||
public Credential(Guid token, AccountEx accountInfo) : this()
|
||||
{
|
||||
Token = token;
|
||||
AccountInfo = accountInfo;
|
||||
|
@ -41,12 +46,17 @@ public class Credential
|
|||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// 登录请求取消。
|
||||
/// </summary>
|
||||
internal CancellationTokenSource LoginRequestCancellationTokenSource { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回当前凭据包含的令牌。
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Token { get; set; }
|
||||
public Guid Token { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回当前凭据状态
|
||||
|
@ -86,10 +96,28 @@ public class Credential
|
|||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 返回空凭据。
|
||||
/// </summary>
|
||||
public static Credential Empty => new Credential();
|
||||
|
||||
public static Credential ReadOnlyOne =>
|
||||
new Credential(Guid.Empty, new AccountEx("", "Read-Only", "", "", "", "", null));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// 检查指定的凭据是否为空凭据。
|
||||
/// </summary>
|
||||
/// <param name="cred"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsEmpty(Credential cred)
|
||||
{
|
||||
return cred.Token == Guid.Empty;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -13,9 +13,20 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
{
|
||||
#region Variables
|
||||
|
||||
private const int KEEP_ALIVE_TIMEOUT_SEC = 60;
|
||||
|
||||
private readonly object _syncRoot = new();
|
||||
|
||||
private readonly Dictionary<string, Credential> _dictLoginCredentials = new ();
|
||||
/// <summary>
|
||||
/// 已登录的凭据。
|
||||
/// </summary>
|
||||
private readonly Dictionary<Guid, Credential> _dictCredentialsLoggedIn = new ();
|
||||
|
||||
/// <summary>
|
||||
/// 正在等在登录请求确认的凭据。
|
||||
/// </summary>
|
||||
private readonly Dictionary<Guid, Credential> _dictCredentialsRequesting = new ();
|
||||
|
||||
private readonly PeriodicJob _threadMonitorCred;
|
||||
private bool _isInitialized;
|
||||
private int _maxCredentialAllowed;
|
||||
|
@ -42,9 +53,18 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
public bool IsSupportMultiUserLogin => _maxCredentialAllowed > 1;
|
||||
|
||||
/// <summary>
|
||||
/// 返回已登录的凭据。
|
||||
/// 返回已登录的用户凭据的数量。
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, Credential> Credentials => _dictLoginCredentials;
|
||||
public int LoggedInCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _dictCredentialsLoggedIn.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -62,23 +82,40 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
_isInitialized = true;
|
||||
_maxCredentialAllowed = isSupportMultiUsersLogin ? int.MaxValue : 1;
|
||||
}
|
||||
|
||||
|
||||
private bool OnTimer()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
foreach (var kvp in _dictLoginCredentials)
|
||||
var removableList = new List<Guid>();
|
||||
foreach (var kvp in _dictCredentialsLoggedIn)
|
||||
{
|
||||
var cred = kvp.Value;
|
||||
if ((DateTime.Now - cred.LastAliveTime).TotalSeconds > 60)
|
||||
{
|
||||
// 如果当前凭据超过60s未激活一次,表示客户端可能已经离线,移除
|
||||
cred.State = CredentialState.Expired;
|
||||
EV.PostLoginBySameUser(cred);
|
||||
}
|
||||
if ((DateTime.Now - cred.LastAliveTime).TotalSeconds > KEEP_ALIVE_TIMEOUT_SEC)
|
||||
EV.PostLoginBySameUser(cred.Token, new Credential());
|
||||
}
|
||||
|
||||
if (removableList.Count > 0)
|
||||
{
|
||||
foreach (var token in removableList)
|
||||
_dictCredentialsLoggedIn.Remove(token);
|
||||
}
|
||||
|
||||
removableList.Clear();
|
||||
foreach (var kvp in _dictCredentialsRequesting)
|
||||
{
|
||||
var cred = kvp.Value;
|
||||
if ((DateTime.Now - cred.LastAliveTime).TotalSeconds > KEEP_ALIVE_TIMEOUT_SEC)
|
||||
removableList.Add(kvp.Key);
|
||||
}
|
||||
|
||||
if (removableList.Count > 0)
|
||||
{
|
||||
foreach (var token in removableList)
|
||||
_dictCredentialsRequesting.Remove(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -87,11 +124,11 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
internal bool CheckHasLoggedIn(string userName)
|
||||
internal bool IsLoggedIn(string userName)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _dictLoginCredentials.Values.FirstOrDefault(x => x.AccountInfo.LoginName == userName) != null;
|
||||
return _dictCredentialsLoggedIn.Values.FirstOrDefault(x => x.AccountInfo.LoginName == userName) != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,11 +137,24 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
internal bool CheckHasLoggedInByToken(string token)
|
||||
internal bool IsLoggedIn(Guid token)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _dictLoginCredentials.ContainsKey(token);
|
||||
return _dictCredentialsLoggedIn.ContainsKey(token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查指定的令牌是否已经过期。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
internal bool IsTokenExpired(Guid token)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _dictCredentialsLoggedIn.ContainsKey(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,16 +163,14 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
/// </summary>
|
||||
/// <param name="token">客户端登录凭据令牌。</param>
|
||||
/// <returns></returns>
|
||||
public CredentialKeepAliveResults KeepAlive(string token)
|
||||
public CredentialKeepAliveResults KeepAlive(Guid token)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_dictLoginCredentials.TryGetValue(token, out var cred))
|
||||
if (_dictCredentialsLoggedIn.TryGetValue(token, out var cred))
|
||||
{
|
||||
if (cred.State == CredentialState.Expired)
|
||||
return CredentialKeepAliveResults.Expired;
|
||||
cred.LastAliveTime = DateTime.Now; // 刷新时间
|
||||
return CredentialKeepAliveResults.Alive;
|
||||
return CredentialKeepAliveResults.Alived;
|
||||
}
|
||||
|
||||
return CredentialKeepAliveResults.NotFound;
|
||||
|
@ -130,21 +178,45 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将指定的凭据加入字典。
|
||||
/// 将凭据加入请求列表。
|
||||
/// </summary>
|
||||
/// <param name="cred"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Add(Credential cred)
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void AddRequestingList(Credential cred)
|
||||
{
|
||||
if (CheckHasLoggedIn(cred.AccountInfo.LoginName))
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_dictCredentialsRequesting.ContainsKey(cred.Token))
|
||||
throw new InvalidOperationException("the credential has been existed in requesting list.");
|
||||
|
||||
_dictCredentialsRequesting[cred.Token] = cred;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将指定的凭据加入字典。
|
||||
/// </summary>
|
||||
/// <param name="cred">待授权的凭据</param>
|
||||
/// <remarks>
|
||||
/// 给凭据授权前必须调用<see cref="AddRequestingList"/>方法将凭据加入到等待列表中。
|
||||
/// </remarks>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Grant(Credential cred)
|
||||
{
|
||||
if (IsLoggedIn(cred.AccountInfo.LoginName))
|
||||
throw new Exception($"user {cred.AccountInfo.LoginName} has been logged in.");
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_dictLoginCredentials.Count >= _maxCredentialAllowed)
|
||||
if (_dictCredentialsLoggedIn.Count >= _maxCredentialAllowed)
|
||||
throw new InvalidOperationException("maximum number of login credentials reached");
|
||||
|
||||
_dictLoginCredentials[cred.Token] = cred;
|
||||
if (!_dictCredentialsRequesting.ContainsKey(cred.Token))
|
||||
throw new InvalidOperationException("the credential is not found in requesting list.");
|
||||
|
||||
cred.State = CredentialState.Alive;
|
||||
_dictCredentialsLoggedIn[cred.Token] = cred;
|
||||
_dictCredentialsRequesting.Remove(cred.Token);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,11 +224,23 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
/// 移除指定令牌的凭据。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
public void Remove(string token)
|
||||
public void Remove(Guid token)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_dictLoginCredentials.Remove(token);
|
||||
_dictCredentialsLoggedIn.Remove(token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从登录请求列表中移除指定的凭据。
|
||||
/// </summary>
|
||||
/// <param name="cred"></param>
|
||||
public void RemoveRequesting(Credential cred)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_dictCredentialsRequesting.Remove(cred.Token);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,11 +249,50 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public Credential GetCredentialByUserName(string userName)
|
||||
public Credential GetCredential(string userName)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _dictLoginCredentials.Values.FirstOrDefault(x => x.AccountInfo.LoginName == userName);
|
||||
return _dictCredentialsLoggedIn.Values.FirstOrDefault(x => x.AccountInfo.LoginName == userName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户名的登录凭据。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public Credential GetCredential(Guid token)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _dictCredentialsLoggedIn.TryGetValue(token, out var cred) ? cred : null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户名的正在等在登录请求的凭据。
|
||||
/// </summary>
|
||||
/// <param name="userName">用户名</param>
|
||||
/// <returns></returns>
|
||||
public Credential GetRequestingCredential(string userName)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _dictCredentialsRequesting.Values.FirstOrDefault(x => x.AccountInfo.LoginName == userName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定令牌的正在等在登录请求的凭据。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public Credential GetRequestingCredential(Guid token)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
return _dictCredentialsRequesting.TryGetValue(token, out var cred) ? cred : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,11 +301,11 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public bool ValidateCredential(string token)
|
||||
public bool ValidateCredential(Guid token)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_dictLoginCredentials.TryGetValue(token, out var cred))
|
||||
if (_dictCredentialsLoggedIn.TryGetValue(token, out var cred))
|
||||
{
|
||||
return cred.State == CredentialState.Alive;
|
||||
}
|
||||
|
@ -199,9 +322,9 @@ public class CredentialManager : Singleton<CredentialManager>
|
|||
/// 创建一个令牌。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GenerateToken()
|
||||
public static Guid GenerateToken()
|
||||
{
|
||||
return Guid.NewGuid().ToString("N");
|
||||
return Guid.NewGuid();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ServiceModel;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -9,12 +10,12 @@ namespace Aitex.Core.Account
|
|||
[ServiceKnownType(typeof(CredentialKeepAliveResults))]
|
||||
[ServiceKnownType(typeof(CredentialState))]
|
||||
[ServiceKnownType(typeof(LoginRequestResults))]
|
||||
[ServiceKnownType(typeof(Credential))]
|
||||
[ServiceKnownType(typeof(AccountEx))]
|
||||
[ServiceKnownType(typeof(LoginResult))]
|
||||
[ServiceContract]
|
||||
public interface IAccountService
|
||||
{
|
||||
[OperationContract]
|
||||
LoginResult Login(string accountId, string password);
|
||||
|
||||
[OperationContract]
|
||||
void Logout(string accountId);
|
||||
|
||||
|
@ -97,17 +98,22 @@ namespace Aitex.Core.Account
|
|||
bool DeleteAccountEx(string loginName);
|
||||
|
||||
[OperationContract]
|
||||
Task<LoginRequestResults> LoginEx(string userName, string password, string role,
|
||||
Task<LoginResult> LoginEx(string userName, string password, string role,
|
||||
LoginClientInfo clientInfo);
|
||||
|
||||
[OperationContract]
|
||||
void CancelLoginRequest(string userName);
|
||||
|
||||
|
||||
[OperationContract]
|
||||
void LogoutEx(string sessionId);
|
||||
void ConfirmLoginRequest(Credential requestingCred);
|
||||
|
||||
[OperationContract]
|
||||
CredentialKeepAliveResults KeepAlive(string token);
|
||||
void RejectLoginRequest(Credential requestingCred);
|
||||
|
||||
[OperationContract]
|
||||
void LogoutEx(Guid token);
|
||||
|
||||
[OperationContract]
|
||||
CredentialKeepAliveResults KeepAlive(Guid token);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,51 +7,46 @@ namespace Aitex.Core.Account
|
|||
[Serializable]
|
||||
public class LoginResult
|
||||
{
|
||||
|
||||
#region Constructors
|
||||
|
||||
public LoginResult()
|
||||
{
|
||||
Credential = Credential.Empty;
|
||||
Result = LoginRequestResults.Error;
|
||||
}
|
||||
|
||||
public LoginResult(LoginRequestResults result) : this(result, Credential.Empty)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public LoginResult(LoginRequestResults result, Credential cred)
|
||||
{
|
||||
Result = result;
|
||||
Credential = cred;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回是否登录成功。
|
||||
/// </summary>
|
||||
public bool ActSucc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回登录成功后RT分配的唯一识别码。
|
||||
/// <remarks>
|
||||
/// 该唯一识别码用于在RT区分每一个不同的客户端连接。
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
public string Token { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回登录的账户信息。
|
||||
/// </summary>
|
||||
public Account AccountInfo { get; set; }
|
||||
|
||||
public AccountEx AccountEx { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回登录结果描述。
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回登录时间。
|
||||
/// </summary>
|
||||
public DateTime LoginTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回客户端IP地址。
|
||||
/// </summary>
|
||||
public string LoginIP { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置或返回客户端Port。
|
||||
/// </summary>
|
||||
public int LoginPort { get; set; }
|
||||
public LoginRequestResults Result { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录凭据。
|
||||
/// </summary>
|
||||
public Credential Credential { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{AccountEx.LoginName} from {LoginIP}:{LoginPort}";
|
||||
return Result.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,29 +5,46 @@ namespace Aitex.Core.Account;
|
|||
/// </summary>
|
||||
public enum LoginRequestResults
|
||||
{
|
||||
None = -1,
|
||||
WrongPwd = 1,
|
||||
HasLogin = 2,
|
||||
NoMatchRole = 3,
|
||||
NoSession = 4,
|
||||
NoMatchUser = 5,
|
||||
Error,
|
||||
WrongPwd,
|
||||
NoMatchRole,
|
||||
NoMatchUser,
|
||||
Confirmed,
|
||||
Rejected,
|
||||
Timeout,
|
||||
Canceled
|
||||
RequstingLogin
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 凭据状态。
|
||||
/// </summary>
|
||||
public enum CredentialState
|
||||
{
|
||||
/// <summary>
|
||||
/// 等待系统校验登录请求。
|
||||
/// </summary>
|
||||
Requesting,
|
||||
|
||||
/// <summary>
|
||||
/// 凭据有效。
|
||||
/// </summary>
|
||||
Alive,
|
||||
Expired
|
||||
|
||||
/// <summary>
|
||||
/// 已登录的用户确认了新的登录请求。
|
||||
/// </summary>
|
||||
Confirmed,
|
||||
|
||||
/// <summary>
|
||||
/// 已登录的用户拒绝新的登录请求。
|
||||
/// </summary>
|
||||
Reject
|
||||
}
|
||||
|
||||
public enum CredentialKeepAliveResults
|
||||
{
|
||||
NotFound,
|
||||
Alive,
|
||||
Expired
|
||||
Alived
|
||||
}
|
||||
|
||||
public class Misc
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Aitex.Core.Account;
|
||||
using Aitex.Core.Util;
|
||||
|
@ -80,11 +81,11 @@ namespace Aitex.Core.RT.Event
|
|||
}
|
||||
}
|
||||
|
||||
public static void PostLoginBySameUser(Credential credential)
|
||||
public static void PostLoginBySameUser(Guid token, Credential requestedCredential)
|
||||
{
|
||||
if (InnerEventManager != null)
|
||||
{
|
||||
InnerEventManager.PostLoginBySameUser(credential);
|
||||
InnerEventManager.PostLoginBySameUser(token, requestedCredential);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -233,9 +233,10 @@ namespace Aitex.Core.RT.Event
|
|||
|
||||
OP.Subscribe("System.Diagnosis.GenLoginBySameUserEvent", (s, args) =>
|
||||
{
|
||||
var token = args[0].ToString();
|
||||
if(CredentialManager.Instance.Credentials.TryGetValue(token, out var cred))
|
||||
PostLoginBySameUser(cred);
|
||||
var token = (Guid)args[0];
|
||||
var cred = CredentialManager.Instance.GetCredential(token);
|
||||
if(cred != null)
|
||||
PostLoginBySameUser(cred.Token, new Credential());
|
||||
else
|
||||
EV.PostWarningLog("Diagnosis", $"The credential with token {token} does not found.");
|
||||
return true;
|
||||
|
@ -472,14 +473,14 @@ namespace Aitex.Core.RT.Event
|
|||
_writerToLog.WriteEvent(eventItem);
|
||||
}
|
||||
|
||||
public void PostLoginBySameUser(Credential credential)
|
||||
public void PostLoginBySameUser(Guid token, Credential requestedCredential)
|
||||
{
|
||||
var eventItem = new EventItem
|
||||
{
|
||||
Type = EventType.LoginBySameUser_Notify,
|
||||
Description = credential.Token,
|
||||
Description = token.ToString(),
|
||||
OccuringTime = DateTime.Now,
|
||||
Tag = credential
|
||||
Tag = requestedCredential
|
||||
};
|
||||
_eventQueue.Enqueue(eventItem);
|
||||
_writerToLog.WriteEvent(eventItem);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Aitex.Core.Account;
|
||||
using Aitex.Core.Util;
|
||||
|
@ -22,7 +23,7 @@ namespace Aitex.Core.RT.Event
|
|||
|
||||
void PostKickoutMessage(string message);
|
||||
|
||||
void PostLoginBySameUser(Credential credential);
|
||||
void PostLoginBySameUser(Guid token, Credential requestedCredential);
|
||||
|
||||
void PostSoundMessage(string message);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -28,7 +27,7 @@ namespace MECF.Framework.Common.Account
|
|||
// 旧的_Account.xml文件路径,为兼容已有的账户配置。
|
||||
private readonly string _oldAccountXmlFile = PathManager.GetCfgDir() + "Account//_Account.xml";
|
||||
|
||||
private readonly object _syncRoot = new();
|
||||
private readonly SemaphoreSlim _syncRoot = new SemaphoreSlim(1, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -36,18 +35,18 @@ namespace MECF.Framework.Common.Account
|
|||
|
||||
public AccountExManager()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 返回角色加载器。
|
||||
/// </summary>
|
||||
public RoleLoader RoleLoader { get; private set; }
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
@ -81,7 +80,7 @@ namespace MECF.Framework.Common.Account
|
|||
|
||||
// 默认不支持多用户登录。
|
||||
CredentialManager.Instance.Initialize(false);
|
||||
|
||||
|
||||
RoleLoader = new RoleLoader(_scAccountLocalFile);
|
||||
RoleLoader.Load();
|
||||
|
||||
|
@ -91,7 +90,11 @@ namespace MECF.Framework.Common.Account
|
|||
}
|
||||
}
|
||||
|
||||
private RemoteEndpointMessageProperty GetCurrentEndPoint()
|
||||
/// <summary>
|
||||
/// 获取WCF客户端IP信息。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private RemoteEndpointMessageProperty GetCurrentWCFClientEndPoint()
|
||||
{
|
||||
var context = OperationContext.Current;
|
||||
var prop = context.IncomingMessageProperties;
|
||||
|
@ -100,166 +103,208 @@ namespace MECF.Framework.Common.Account
|
|||
return endpoint;
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, CancellationTokenSource> _dictLoginCts = new ();
|
||||
|
||||
public async Task<LoginRequestResults> WaitUserLogout(Credential user, Credential newUser)
|
||||
/// <summary>
|
||||
/// 等待已登录的用户确认是否允许新的登录请求。
|
||||
/// </summary>
|
||||
/// <param name="userLoggedIn">已登录用户的凭据。</param>
|
||||
/// <param name="userRequesting">新用户的登录凭据。</param>
|
||||
/// <returns></returns>
|
||||
private async Task<LoginRequestResults> RequestAndWaitLoginConfirmation(Credential userLoggedIn,
|
||||
Credential userRequesting)
|
||||
{
|
||||
// 如果当前用户名有对应的CancellationTokenSource,并且没有触发取消,说明某个客户端正在使用当前用户发起登录请求,此时
|
||||
// 不可重复请求登录。
|
||||
if (_dictLoginCts.TryGetValue(user.AccountInfo.LoginName, out var cts)
|
||||
&& cts is { IsCancellationRequested: false })
|
||||
{
|
||||
// 该用户名正在请求登录,拒绝新的登录请求
|
||||
EV.PostWarningLog(ModuleName.System.ToString(), "The user has been requesting login, please try again later.");
|
||||
}
|
||||
|
||||
// 用户已登录,需要已登录的客户端确认退出后,再放行凭据
|
||||
cts = new CancellationTokenSource();
|
||||
_dictLoginCts.Add(user.AccountInfo.LoginName, cts);
|
||||
var ct = cts.Token;
|
||||
|
||||
// 等待已登录用户响应,返回结果;
|
||||
// 1. Rejected,拒绝新的登录请求
|
||||
// 2. Logged Out,主动注销,允许新的登录请求
|
||||
// 3. Timeout,超时没有响应,保持原用户的登录凭据
|
||||
return await Task.Run(async () =>
|
||||
{
|
||||
// 请求已登录的客户端确认是否同意注销
|
||||
EV.PostLoginBySameUser(user);
|
||||
// 通知已登录的用户,其它客户端使用该用户名登录,是否允许登录
|
||||
EV.PostLoginBySameUser(userLoggedIn.Token, userRequesting);
|
||||
|
||||
var ct = userRequesting.LoginRequestCancellationTokenSource.Token;
|
||||
|
||||
// 等待已登录的凭据被移除(客户端注销)
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!CredentialManager.Instance.CheckHasLoggedInByToken(user.Token))
|
||||
if (userRequesting.State == CredentialState.Confirmed)
|
||||
{
|
||||
// 客户端已注销,可以放行新的凭据
|
||||
CredentialManager.Instance.Add(newUser);
|
||||
EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedIn, user.AccountInfo.LoginName);
|
||||
CredentialManager.Instance.Grant(userRequesting);
|
||||
EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedIn,
|
||||
userLoggedIn.AccountInfo.LoginName);
|
||||
return await Task.FromResult(LoginRequestResults.Confirmed);
|
||||
}
|
||||
|
||||
if (userRequesting.State == CredentialState.Reject)
|
||||
{
|
||||
// 已登录用户拒绝了登录请求
|
||||
EV.PostInfoLog(ModuleName.System.ToString(),
|
||||
$"User {userRequesting.AccountInfo.LoginName}'s login request from {userRequesting.LoginIP}:{userRequesting.LoginPort} is rejected");
|
||||
|
||||
CredentialManager.Instance.RemoveRequesting(userRequesting);
|
||||
return await Task.FromResult(LoginRequestResults.Rejected);
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
if (sw.Elapsed.TotalSeconds > 30)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// 等待客户端注销超时
|
||||
_dictLoginCts.Remove(user.AccountInfo.LoginName);
|
||||
return LoginRequestResults.Timeout;
|
||||
|
||||
}, ct);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<LoginRequestResults> RequestLogin(string loginName, string password, string role,
|
||||
/// <summary>
|
||||
/// 登录。
|
||||
/// </summary>
|
||||
/// <param name="userName">用户名</param>
|
||||
/// <param name="password">密码</param>
|
||||
/// <param name="roleID">角色ID</param>
|
||||
/// <param name="clientInfo">发起登录请求的客户端信息</param>
|
||||
/// <returns><see cref="LoginRequestResults"/></returns>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
public async Task<LoginResult> Login(string userName, string password, string roleID,
|
||||
LoginClientInfo clientInfo)
|
||||
{
|
||||
Task<LoginRequestResults> ret;
|
||||
|
||||
if (!Monitor.Wait(_syncRoot, 40000))
|
||||
throw new TimeoutException($"timeout to lock the credential manager.");
|
||||
|
||||
var endPoint = GetCurrentEndPoint();
|
||||
|
||||
var endPoint = GetCurrentWCFClientEndPoint();
|
||||
|
||||
try
|
||||
{
|
||||
var accountList = RoleLoader.AccountList;
|
||||
|
||||
var matchedAccount = accountList.FirstOrDefault(x => x.LoginName == loginName);
|
||||
var matchedAccount = accountList.FirstOrDefault(x => x.LoginName == userName);
|
||||
if (matchedAccount == null)
|
||||
// 用户不存在
|
||||
return await Task.FromResult(LoginRequestResults.NoMatchUser);
|
||||
return await Task.FromResult(new LoginResult(LoginRequestResults.NoMatchUser));
|
||||
|
||||
if (matchedAccount.Password != password)
|
||||
// 密码错误
|
||||
return await Task.FromResult(LoginRequestResults.WrongPwd);
|
||||
return await Task.FromResult(new LoginResult(LoginRequestResults.WrongPwd));
|
||||
|
||||
// 查找当前用户的登录角色是否存在
|
||||
var matchedRole = matchedAccount.RoleIDs.FirstOrDefault(x => x == role);
|
||||
var matchedRole = matchedAccount.RoleIDs.FirstOrDefault(x => x == roleID);
|
||||
if (matchedRole == null)
|
||||
// 找不到角色
|
||||
return await Task.FromResult(LoginRequestResults.NoMatchRole);
|
||||
return await Task.FromResult(new LoginResult(LoginRequestResults.NoMatchRole));
|
||||
|
||||
|
||||
// 同一用户名不可重复请求登录。
|
||||
var requestingCred =
|
||||
CredentialManager.Instance.GetRequestingCredential(userName);
|
||||
|
||||
if (requestingCred != null)
|
||||
{
|
||||
// 该用户名正在请求登录,拒绝新的登录请求
|
||||
return await Task.FromResult(new LoginResult(LoginRequestResults.RequstingLogin));
|
||||
}
|
||||
|
||||
// 创建新凭据
|
||||
var newCred = new Credential(CredentialManager.GenerateToken(), matchedAccount)
|
||||
{
|
||||
LoginIP = endPoint.Address,
|
||||
LoginPort = endPoint.Port,
|
||||
LoginTime = DateTime.Now
|
||||
LoginPort = endPoint.Port
|
||||
};
|
||||
|
||||
if(CredentialManager.Instance.Credentials.Count == 0)
|
||||
// 添加凭据到登录请求列表,Grant时需要请求列表中存在此凭据。
|
||||
CredentialManager.Instance.AddRequestingList(newCred);
|
||||
|
||||
if (CredentialManager.Instance.LoggedInCount == 0)
|
||||
{
|
||||
// 没有用户登录,直接发放凭据
|
||||
CredentialManager.Instance.Add(newCred);
|
||||
EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedIn, loginName);
|
||||
return await Task.FromResult(LoginRequestResults.Confirmed);
|
||||
// 没有用户登录,直接发放凭据
|
||||
CredentialManager.Instance.Grant(newCred);
|
||||
EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedIn, userName);
|
||||
return await Task.FromResult(new LoginResult(LoginRequestResults.Confirmed, newCred));
|
||||
}
|
||||
|
||||
|
||||
if (CredentialManager.Instance.IsSupportMultiUserLogin)
|
||||
{
|
||||
// 查找当前请求的用户是否已经登录
|
||||
var loggedCred = CredentialManager.Instance.GetCredentialByUserName(loginName);
|
||||
|
||||
var loggedCred = CredentialManager.Instance.GetCredential(userName);
|
||||
|
||||
// 支持多用户同时登录
|
||||
if (loggedCred == null)
|
||||
{
|
||||
// 用户未登录,直接放行凭据
|
||||
CredentialManager.Instance.Add(newCred);
|
||||
EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedIn, loginName);
|
||||
return await Task.FromResult(LoginRequestResults.Confirmed);
|
||||
CredentialManager.Instance.Grant(newCred);
|
||||
EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedIn, userName);
|
||||
return await Task.FromResult(new LoginResult(LoginRequestResults.Confirmed, newCred));
|
||||
}
|
||||
|
||||
return await WaitUserLogout(loggedCred, newCred);
|
||||
var ret = await RequestAndWaitLoginConfirmation(loggedCred, newCred);
|
||||
return ret == LoginRequestResults.Confirmed ? new LoginResult(ret, newCred) : new LoginResult(ret);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CredentialManager.Instance.Credentials.Count > 1)
|
||||
if (CredentialManager.Instance.LoggedInCount > 1)
|
||||
{
|
||||
EV.PostWarningLog(ModuleName.System.ToString(),
|
||||
$"{nameof(CredentialManager)} does not support multiple users login but more than one credentials found.");
|
||||
}
|
||||
|
||||
var loggedCred = CredentialManager.Instance.Credentials.First().Value;
|
||||
|
||||
return await WaitUserLogout(loggedCred, newCred);
|
||||
var loggedCred = CredentialManager.Instance.GetCredential(userName);
|
||||
|
||||
var ret = await RequestAndWaitLoginConfirmation(loggedCred, newCred);
|
||||
return ret == LoginRequestResults.Confirmed ? new LoginResult(ret, newCred) : new LoginResult(ret);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.Error(ex.Message, ex);
|
||||
return await Task.FromResult(LoginRequestResults.None);
|
||||
return await Task.FromResult(new LoginResult(LoginRequestResults.Error));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dictLoginCts.Remove(loginName);
|
||||
Monitor.Exit(_syncRoot);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登录请求发起端取消登录请求。
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
public void CancelLoginRequest(string userName)
|
||||
{
|
||||
if (_dictLoginCts.TryGetValue(userName, out var cts))
|
||||
cts.Cancel();
|
||||
}
|
||||
|
||||
internal void Logout(string token)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
var cred = CredentialManager.Instance.GetRequestingCredential(userName);
|
||||
if (cred != null)
|
||||
{
|
||||
if (CredentialManager.Instance.Credentials.TryGetValue(token, out var cred))
|
||||
{
|
||||
EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedOff,
|
||||
cred.AccountInfo.LoginName);
|
||||
|
||||
CredentialManager.Instance.Remove(token);
|
||||
}
|
||||
cred.LoginRequestCancellationTokenSource.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ConfirmedLoginRequest(Credential requestingCred)
|
||||
{
|
||||
var cred = CredentialManager.Instance.GetRequestingCredential(requestingCred.Token);
|
||||
if (cred != null)
|
||||
cred.State = CredentialState.Confirmed;
|
||||
}
|
||||
|
||||
public void RejectLoginRequest(Credential requestingCred)
|
||||
{
|
||||
var cred = CredentialManager.Instance.GetRequestingCredential(requestingCred.Token);
|
||||
if (cred != null)
|
||||
cred.State = CredentialState.Reject;
|
||||
}
|
||||
|
||||
internal void Logout(Guid token)
|
||||
{
|
||||
var cred = CredentialManager.Instance.GetCredential(token);
|
||||
if (cred != null)
|
||||
{
|
||||
EV.PostMessage(ModuleName.System.ToString(), EventEnum.UserLoggedOff,
|
||||
cred.AccountInfo.LoginName);
|
||||
}
|
||||
|
||||
CredentialManager.Instance.Remove(token);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,11 @@ namespace MECF.Framework.Common.Account.Extends
|
|||
|
||||
#region Constructors
|
||||
|
||||
public AccountEx()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AccountEx(string id, string loginName, string password, string firstName, string lastName, string email,
|
||||
List<string> rolesBelongTo, string description = "")
|
||||
{
|
||||
|
@ -116,7 +121,7 @@ namespace MECF.Framework.Common.Account.Extends
|
|||
get => _mStrRoles;
|
||||
set => _mStrRoles = value;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,11 +212,15 @@ namespace MECF.Framework.Common.Account.Extends
|
|||
var item3 = new AccountEx(strUserId, strLoginName, strPassword, strFirstName, strLastName, strEmail, lstRolesBelongTo, strDescription);
|
||||
lstUsers.Add(item3);
|
||||
}
|
||||
var item4 = new AccountEx("-1", "admin", "admin", "", "", "", new List<string> { "-1" })
|
||||
var admin = new AccountEx("-1", "admin", "admin", "", "", "", new List<string> { "-1" })
|
||||
{
|
||||
IsSuper = true
|
||||
};
|
||||
lstUsers.Add(item4);
|
||||
lstUsers.Add(admin);
|
||||
|
||||
var readOnly = new AccountEx("-2", "Read-Only", "read-only", "", "", "", new List<string> { "-1" });
|
||||
lstUsers.Add(readOnly);
|
||||
|
||||
_accountList = lstUsers;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Aitex.Core.Account;
|
||||
using MECF.Framework.Common.CommonData;
|
||||
|
||||
namespace MECF.Framework.Common.Account.Extends
|
||||
|
@ -6,39 +7,54 @@ namespace MECF.Framework.Common.Account.Extends
|
|||
[Serializable]
|
||||
public class UserContext : NotifiableItem
|
||||
{
|
||||
#region Variables
|
||||
|
||||
private Credential _cred;
|
||||
private string _loginName;
|
||||
|
||||
public string LoginName
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public Credential Credential
|
||||
{
|
||||
get => _loginName;
|
||||
get => _cred;
|
||||
set
|
||||
{
|
||||
_loginName = value;
|
||||
InvokePropertyChanged();
|
||||
_cred = value;
|
||||
InvokePropertyChanged(nameof(Token));
|
||||
InvokePropertyChanged(nameof(LoginName));
|
||||
InvokePropertyChanged(nameof(LoginTime));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Guid Token => _cred.Token;
|
||||
|
||||
public string LoginName => _cred?.AccountInfo?.LoginName ?? "";
|
||||
|
||||
public DateTime LoginTime => _cred?.LoginTime ?? DateTime.MinValue;
|
||||
|
||||
public Role Role { get; set; }
|
||||
|
||||
public DateTime LoginTime { get; set; }
|
||||
|
||||
public DateTime LastAccessTime { get; set; }
|
||||
|
||||
public string Token { get; set; }
|
||||
|
||||
public string Language { get; private set; }
|
||||
|
||||
public bool IsLogin { get; set; }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
LoginName = string.Empty;
|
||||
Role = null;
|
||||
LoginTime = DateTime.MinValue;
|
||||
LastAccessTime = DateTime.MinValue;
|
||||
Token = string.Empty;
|
||||
Language = string.Empty;
|
||||
IsLogin = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_cred = Credential.Empty;
|
||||
Role = null;
|
||||
LastAccessTime = DateTime.MinValue;
|
||||
Language = string.Empty;
|
||||
IsLogin = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Aitex.Core.Account;
|
||||
using Aitex.Core.Util;
|
||||
|
@ -13,17 +13,7 @@ namespace MECF.Framework.UI.Core.Accounts
|
|||
public AccountServiceClient()
|
||||
{
|
||||
}
|
||||
|
||||
public LoginResult Login(string accountId, string accountPwd)
|
||||
{
|
||||
LoginResult result = null;
|
||||
WCFProxy.Using(delegate(IAccountService svc)
|
||||
{
|
||||
result = svc.Login(accountId, accountPwd);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void Logout(string accountId)
|
||||
{
|
||||
WCFProxy.Using(delegate(IAccountService svc)
|
||||
|
@ -288,10 +278,10 @@ namespace MECF.Framework.UI.Core.Accounts
|
|||
return result;
|
||||
}
|
||||
|
||||
public async Task<LoginRequestResults> LoginEx(string userName, string password, string role,
|
||||
public async Task<LoginResult> LoginEx(string userName, string password, string role,
|
||||
LoginClientInfo clientInfo)
|
||||
{
|
||||
LoginRequestResults result = default;
|
||||
LoginResult result = default;
|
||||
await WCFProxy.AsyncUsing(async delegate(IAccountService svc)
|
||||
{
|
||||
result = await svc.LoginEx(userName, password, role, clientInfo);
|
||||
|
@ -308,7 +298,23 @@ namespace MECF.Framework.UI.Core.Accounts
|
|||
});
|
||||
}
|
||||
|
||||
public void LogoutEx(string token)
|
||||
public void ConfirmLoginRequest(Credential requestingCred)
|
||||
{
|
||||
WCFProxy.Using(delegate(IAccountService svc)
|
||||
{
|
||||
svc.ConfirmLoginRequest(requestingCred);
|
||||
});
|
||||
}
|
||||
|
||||
public void RejectLoginRequest(Credential requestingCred)
|
||||
{
|
||||
WCFProxy.Using(delegate(IAccountService svc)
|
||||
{
|
||||
svc.RejectLoginRequest(requestingCred);
|
||||
});
|
||||
}
|
||||
|
||||
public void LogoutEx(Guid token)
|
||||
{
|
||||
WCFProxy.Using(delegate(IAccountService svc)
|
||||
{
|
||||
|
@ -316,7 +322,7 @@ namespace MECF.Framework.UI.Core.Accounts
|
|||
});
|
||||
}
|
||||
|
||||
public CredentialKeepAliveResults KeepAlive(string token)
|
||||
public CredentialKeepAliveResults KeepAlive(Guid token)
|
||||
{
|
||||
var result = CredentialKeepAliveResults.NotFound;
|
||||
WCFProxy.Using(delegate(IAccountService svc)
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
<Window x:Class="MECF.Framework.UI.Core.Accounts.GonaMainLogin"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:aero="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar"
|
||||
xmlns:validationRules2="clr-namespace:Aitex.Core.UI.ValidationRules"
|
||||
WindowState="Maximized"
|
||||
WindowStyle="SingleBorderWindow"
|
||||
Background="{DynamicResource Login_BG}"
|
||||
ShowInTaskbar="True"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
<Window.Resources>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="FontSize" Value="20"/>
|
||||
<Setter Property="FontFamily" Value="Arial,SimSun" />
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Border BorderBrush="DarkBlue" BorderThickness="0,0,1,1">
|
||||
<Border BorderBrush="LightBlue" BorderThickness="1,1,0,0">
|
||||
<Grid Width="450" Height="350">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="50"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.Effect>
|
||||
<DropShadowEffect BlurRadius="10" ShadowDepth="0"/>
|
||||
</Grid.Effect>
|
||||
<Path Data="M23.5,0.5 L426.5,0.5 449.5,23.5 449.5,243.2 437.5,257.2 437.5,294.5 406.5,324.5 43.5,324.5 12.5,294.5 12.5,257.2 0.5,243.2 0.5,23.5 z" HorizontalAlignment="Left" Margin="0,22,0,0" Grid.RowSpan="3" Stretch="Fill" Width="450" StrokeThickness="2" Fill="{DynamicResource Login_MainOuter_BG}" Stroke="{DynamicResource Login_MainOuter_BD}"/>
|
||||
<Path Data="M21.44508,0.5 L429.58238,0.5 449.5,21.436306 449.5,243.2 437.5,257.2 437.5,294.5 406.5,324.5 43.5,324.5 12.5,294.5 12.5,257.2 0.5,243.2 0.5,22.468153 z" Margin="6,-21.5,6,6.5" Grid.RowSpan="2" Stretch="Fill" Grid.Row="1" StrokeThickness="2" Fill="{DynamicResource Login_MainInner_BG}" Stroke="{DynamicResource Login_MainInner_BD}"/>
|
||||
<Grid Width="350">
|
||||
<Path Data="M25.5,0.5 L324.5,0.5 349.5,25 324.5,49.5 25.5,49.5 0.5,25 z" Stretch="Fill" StrokeThickness="2" Fill="{DynamicResource Login_TopOuter_BG}" Stroke="{DynamicResource Login_TopOuter_BD}"/>
|
||||
<Path Data="M21.5,0.5 L328.5,0.5 349.5,25 328.5,49.5 21.5,49.5 0.5,25 z" Stretch="Fill" Margin="8,5" Fill="{DynamicResource Login_TopInner_BG}" Stroke="{DynamicResource Login_TopInner_BD}"/>
|
||||
<TextBlock TextWrapping="Wrap" Text="User Login" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontFamily="Arial" FontSize="24" FontWeight="Bold">
|
||||
<TextBlock.Effect>
|
||||
<DropShadowEffect BlurRadius="0" ShadowDepth="2"/>
|
||||
</TextBlock.Effect>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="130"/>
|
||||
<ColumnDefinition Width="220"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="60"/>
|
||||
<RowDefinition Height="60"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Grid.Row="0" Grid.Column="0" Name="labelUserName" Content="{DynamicResource GlobalLableUserName}" Foreground="{DynamicResource FG_White}" VerticalAlignment="Center" HorizontalAlignment="Right">
|
||||
<Label.Effect>
|
||||
<DropShadowEffect BlurRadius="0" ShadowDepth="2"/>
|
||||
</Label.Effect>
|
||||
</Label>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Name="textBoxUserName" Style="{DynamicResource LoginTextBox}" VerticalAlignment="Center" Height="40">
|
||||
<Binding Path="UserName" UpdateSourceTrigger="LostFocus">
|
||||
<Binding.ValidationRules>
|
||||
<validationRules2:ValidateUserName />
|
||||
</Binding.ValidationRules>
|
||||
</Binding>
|
||||
</TextBox>
|
||||
<Label Grid.Row="1" Grid.Column="0" Name="label2" Foreground="{DynamicResource FG_White}" Content="{DynamicResource GlobalLableUserPassword}" VerticalAlignment="Center" HorizontalAlignment="Right">
|
||||
<Label.Effect>
|
||||
<DropShadowEffect BlurRadius="0" ShadowDepth="2"/>
|
||||
</Label.Effect>
|
||||
</Label>
|
||||
<PasswordBox Grid.Row="1" Grid.Column="1" Name="passwordBox" Style="{DynamicResource LoginPasswordBox}" VerticalAlignment="Center" Height="40">
|
||||
</PasswordBox>
|
||||
<Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="" Name="LabelResult" Foreground="{DynamicResource FG_White}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="3" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Bottom">
|
||||
<Button Style="{DynamicResource LoginButton}" Click="OnLoginClicked" FontSize="18" Height="40" Width="120" FontWeight="Bold" Content="{DynamicResource GlobalLableButtonLogin}" IsDefault="True"/>
|
||||
<Button Style="{DynamicResource LoginButton}" FontSize="20" Margin="10,0,0,0" Click="OnExitClicked" Height="40" Width="120" FontWeight="Bold" Content="{DynamicResource GlobalLableButtonExit}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Border>
|
||||
</Window>
|
|
@ -1,71 +0,0 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Aitex.Core.Account;
|
||||
using MECF.Framework.UI.Core.Applications;
|
||||
|
||||
namespace MECF.Framework.UI.Core.Accounts
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainLogin.xaml
|
||||
/// </summary>
|
||||
public partial class GonaMainLogin : Window
|
||||
{
|
||||
LoginViewModel viewModel;
|
||||
|
||||
public GonaMainLogin()
|
||||
{
|
||||
InitializeComponent();
|
||||
viewModel = new LoginViewModel();
|
||||
DataContext = viewModel;
|
||||
|
||||
Loaded += OnLoginViewLoaded;
|
||||
}
|
||||
|
||||
private void OnLoginViewLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FocusManager.SetFocusedElement(this, textBoxUserName);
|
||||
}
|
||||
|
||||
private void OnLoginClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
string userName = textBoxUserName.Text;
|
||||
IntPtr p = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(passwordBox.SecurePassword);
|
||||
string passWord = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(p);
|
||||
viewModel.UserName = userName;
|
||||
viewModel.Password = passWord;
|
||||
LoginResult loginResult = AccountClient.Instance.Service.Login(userName, passWord);
|
||||
|
||||
LabelResult.Content = loginResult.Description;
|
||||
|
||||
if (loginResult.ActSucc)
|
||||
{
|
||||
viewModel.SetLoginResult(loginResult);
|
||||
this.DialogResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (loginResult.Description.Contains("already login") && System.Windows.Forms.MessageBox.Show
|
||||
(string.Format(loginResult.Description + "\r\n force logoff?"), UiApplication.Instance.Current.SystemName,
|
||||
System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
|
||||
{
|
||||
AccountClient.Instance.Service.KickUserOut(userName, string.Format("account {0} login from other place", userName));
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = loginResult.Description;
|
||||
MessageBox.Show(message, UiApplication.Instance.Current.SystemName, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExitClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
using System;
|
||||
using Aitex.Core.Account;
|
||||
using Aitex.Core.Util;
|
||||
|
||||
namespace MECF.Framework.UI.Core.Accounts
|
||||
{
|
||||
public class LoginViewModel
|
||||
{
|
||||
private string _userName = "";
|
||||
private string _password = "";
|
||||
|
||||
public string UserName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _userName;
|
||||
}
|
||||
set
|
||||
{
|
||||
_userName = value;
|
||||
//ClearError();
|
||||
//InvokePropertyChanged("UserName");
|
||||
}
|
||||
}
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
return _password;
|
||||
}
|
||||
set
|
||||
{
|
||||
_password = value;
|
||||
//ClearError();
|
||||
//InvokePropertyChanged("Password");
|
||||
}
|
||||
}
|
||||
|
||||
public Account AccountInfo
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public String Token
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Role
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public void SetLoginResult(LoginResult result)
|
||||
{
|
||||
AccountClient.Instance.CurrentUser = result.AccountInfo;
|
||||
AccountInfo = result.AccountInfo;
|
||||
Token = result.Token;
|
||||
Role = AccountInfo.Role;
|
||||
}
|
||||
|
||||
public LoginViewModel()
|
||||
{
|
||||
|
||||
|
||||
|
||||
UserName = string.Empty;
|
||||
Password = string.Empty;
|
||||
|
||||
AccountInfo = new Account();
|
||||
|
||||
//m_password1Property = new PassableProperty<string>(
|
||||
// () => Password,
|
||||
// (val) => { Password = val; }
|
||||
// );
|
||||
}
|
||||
|
||||
//private string m_error = "";
|
||||
//public string Error
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// return m_error;
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// m_error = value;
|
||||
// InvokePropertyChanged("Error");
|
||||
// }
|
||||
//}
|
||||
|
||||
//private readonly PassableProperty<string> m_password1Property;
|
||||
//public PassableProperty<string> Password1Property
|
||||
//{
|
||||
// get { return m_password1Property; }
|
||||
//}
|
||||
|
||||
//private void ClearError()
|
||||
//{
|
||||
// Error = string.Empty;
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
<Window x:Class="MECF.Framework.UI.Core.Accounts.MainLogin"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:aero="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar"
|
||||
xmlns:validationRules2="clr-namespace:Aitex.Core.UI.ValidationRules"
|
||||
Width="400" Height="350"
|
||||
WindowStyle="None"
|
||||
Background="{StaticResource loginBackgroundImg}"
|
||||
ShowInTaskbar="True"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
WindowState="Normal" ResizeMode="NoResize">
|
||||
<Window.Resources>
|
||||
<Style TargetType="{x:Type PasswordBox}">
|
||||
<Setter Property="FontSize" Value="20"></Setter>
|
||||
<Setter Property="Padding" Value="1,5,0,0"></Setter>
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/输入框.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="FontSize" Value="20"/>
|
||||
<Setter Property="FontFamily" Value="Arial,SimSun" />
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
</Style>
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="TextBoxBase">
|
||||
<aero:ListBoxChrome Background="{TemplateBinding Control.Background}" BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="{TemplateBinding Control.BorderThickness}" Name="Bd" RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" SnapsToDevicePixels="True">
|
||||
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
|
||||
</aero:ListBoxChrome>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="UIElement.IsEnabled" Value="False">
|
||||
<Setter Property="aero:ListBoxChrome.Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
|
||||
<Setter Property="Control.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="FontSize" Value="20"></Setter>
|
||||
<Setter Property="Padding" Value="1,5,0,0"></Setter>
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/输入框.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/输入框_选择.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮.png"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮_悬停.png"></ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
<Trigger Property="IsFocused" Value="true">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮_点击.png"></ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--登录窗口样式-->
|
||||
<Style TargetType="Button" x:Key="LoginButton">
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
|
||||
<Setter Property="BorderBrush" Value="Blue" />
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
<Setter Property="FontFamily" Value="Arial,SimSun" />
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="Height" Value="40"></Setter>
|
||||
<Setter Property="Width" Value="116"></Setter>
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮.png" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ButtonBase">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
|
||||
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" Margin="{TemplateBinding Control.Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" >
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮_悬停.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
<!-- When the mouse is pressed, apply a bevel with a narrower BevelWidth to make the button appear to get pressed. -->
|
||||
<Trigger Property="IsFocused" Value="true">
|
||||
<Setter Property="Background" >
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮_点击.png">
|
||||
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Canvas x:Name="canvas" Width="390" Height="340" >
|
||||
<Label Height="40" Name="labelUserName" Content="{DynamicResource GlobalLableUserName}" Width="230" Foreground="White" Canvas.Left="90" Canvas.Top="40" RenderTransformOrigin="0.648,0.75"/>
|
||||
<TextBox Height="40" Name="textBoxUserName" Width="190" FontSize="20" Canvas.Left="95" Canvas.Top="80">
|
||||
<Binding Path="UserName" UpdateSourceTrigger="LostFocus">
|
||||
<Binding.ValidationRules>
|
||||
<validationRules2:ValidateUserName />
|
||||
</Binding.ValidationRules>
|
||||
</Binding>
|
||||
</TextBox>
|
||||
<Label Canvas.Left="95" Canvas.Top="124" Height="40" Name="label2" Width="240" Foreground="White" Content="{DynamicResource GlobalLableUserPassword}" />
|
||||
<PasswordBox Canvas.Left="95" Canvas.Top="169" Height="40" Name="passwordBox" Width="190" >
|
||||
<PasswordBox.Template>
|
||||
<ControlTemplate TargetType="PasswordBox" >
|
||||
<aero:ListBoxChrome Background="{TemplateBinding Control.Background}" BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="{TemplateBinding Control.BorderThickness}" Name="Bd" RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" SnapsToDevicePixels="True">
|
||||
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
|
||||
</aero:ListBoxChrome>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter Property="Background" >
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/输入框_选择.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</PasswordBox.Template>
|
||||
</PasswordBox>
|
||||
<Button Click="OnLoginClicked" FontSize="18" Style="{StaticResource LoginButton}" Canvas.Left="49" Canvas.Top="290" Height="40" Width="116" FontWeight="Bold" Content="{DynamicResource GlobalLableButtonLogin}" IsDefault="True"/>
|
||||
<Button FontSize="20" Style="{StaticResource LoginButton}" Canvas.Left="233" Canvas.Top="290" Click="OnExitClicked" Height="40" Width="116" FontWeight="Bold" Content="{DynamicResource GlobalLableButtonExit}"/>
|
||||
<Label Canvas.Left="135" Height="40" Width="160" Content="{DynamicResource GlobalLableUserLogin}" />
|
||||
<Label Canvas.Left="28" Canvas.Top="224" Content="" Height="40" Name="LabelResult" Width="307" Foreground="White" />
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Window>
|
|
@ -1,71 +0,0 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Aitex.Core.Account;
|
||||
using MECF.Framework.UI.Core.Applications;
|
||||
|
||||
namespace MECF.Framework.UI.Core.Accounts
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainLogin.xaml
|
||||
/// </summary>
|
||||
public partial class MainLogin : Window
|
||||
{
|
||||
LoginViewModel viewModel;
|
||||
|
||||
public MainLogin()
|
||||
{
|
||||
InitializeComponent();
|
||||
viewModel = new LoginViewModel();
|
||||
DataContext = viewModel;
|
||||
|
||||
Loaded += OnLoginViewLoaded;
|
||||
}
|
||||
|
||||
private void OnLoginViewLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FocusManager.SetFocusedElement(this, textBoxUserName);
|
||||
}
|
||||
|
||||
private void OnLoginClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
string userName = textBoxUserName.Text;
|
||||
IntPtr p = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(passwordBox.SecurePassword);
|
||||
string passWord = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(p);
|
||||
viewModel.UserName = userName;
|
||||
viewModel.Password = passWord;
|
||||
LoginResult loginResult = AccountClient.Instance.Service.Login(userName, passWord);
|
||||
|
||||
LabelResult.Content = loginResult.Description;
|
||||
|
||||
if (loginResult.ActSucc)
|
||||
{
|
||||
viewModel.SetLoginResult(loginResult);
|
||||
this.DialogResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (loginResult.Description.Contains("already login") && System.Windows.Forms.MessageBox.Show
|
||||
(string.Format(loginResult.Description + "\r\n force logoff?"), UiApplication.Instance.Current.SystemName,
|
||||
System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
|
||||
{
|
||||
AccountClient.Instance.Service.KickUserOut(userName, string.Format("account {0} login from other place", userName));
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = loginResult.Description;
|
||||
MessageBox.Show(message, UiApplication.Instance.Current.SystemName, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExitClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
<Window x:Class="MECF.Framework.UI.Core.Accounts.PasswordMsgBox"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:aero="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar"
|
||||
xmlns:validationRules2="clr-namespace:Aitex.Core.UI.ValidationRules"
|
||||
Width="400" Height="350"
|
||||
WindowStyle="None"
|
||||
Background="{StaticResource loginBackgroundImg}"
|
||||
ShowInTaskbar="True"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
WindowState="Normal" ResizeMode="NoResize">
|
||||
<Window.Resources>
|
||||
<Style TargetType="{x:Type PasswordBox}">
|
||||
<Setter Property="FontSize" Value="20"></Setter>
|
||||
<Setter Property="Padding" Value="1,5,0,0"></Setter>
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/输入框.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="FontSize" Value="20"/>
|
||||
<Setter Property="FontFamily" Value="Arial,SimSun" />
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
</Style>
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="TextBoxBase">
|
||||
<aero:ListBoxChrome Background="{TemplateBinding Control.Background}" BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="{TemplateBinding Control.BorderThickness}" Name="Bd" RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" SnapsToDevicePixels="True">
|
||||
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
|
||||
</aero:ListBoxChrome>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="UIElement.IsEnabled" Value="False">
|
||||
<Setter Property="aero:ListBoxChrome.Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
|
||||
<Setter Property="Control.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="FontSize" Value="20"></Setter>
|
||||
<Setter Property="Padding" Value="1,5,0,0"></Setter>
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/输入框.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/输入框_选择.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮.png"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮_悬停.png"></ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
<Trigger Property="IsFocused" Value="true">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮_点击.png"></ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--登录窗口样式-->
|
||||
<Style TargetType="Button" x:Key="LoginButton">
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
|
||||
<Setter Property="BorderBrush" Value="Blue" />
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
<Setter Property="FontFamily" Value="Arial,SimSun" />
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="Height" Value="40"></Setter>
|
||||
<Setter Property="Width" Value="116"></Setter>
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮.png" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ButtonBase">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
|
||||
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" Margin="{TemplateBinding Control.Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" >
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮_悬停.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
<!-- When the mouse is pressed, apply a bevel with a narrower BevelWidth to make the button appear to get pressed. -->
|
||||
<Trigger Property="IsFocused" Value="true">
|
||||
<Setter Property="Background" >
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/按钮_点击.png">
|
||||
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Canvas x:Name="canvas" Width="390" Height="340" >
|
||||
<Label Canvas.Left="78" Canvas.Top="88" Height="40" Name="label2" Width="240" Foreground="White" Content="{DynamicResource GlobalLableUserPassword}" />
|
||||
<PasswordBox Canvas.Left="78" Canvas.Top="144" Height="40" Name="passwordBox" Width="190" >
|
||||
<PasswordBox.Template>
|
||||
<ControlTemplate TargetType="PasswordBox" >
|
||||
<aero:ListBoxChrome Background="{TemplateBinding Control.Background}" BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="{TemplateBinding Control.BorderThickness}" Name="Bd" RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" SnapsToDevicePixels="True">
|
||||
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
|
||||
</aero:ListBoxChrome>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter Property="Background" >
|
||||
<Setter.Value>
|
||||
<ImageBrush ImageSource="pack://application:,,,/MECF.Framework.UI.Core;component/Resources/Login/输入框_选择.png">
|
||||
</ImageBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</PasswordBox.Template>
|
||||
</PasswordBox>
|
||||
<Button Click="OnLoginClicked" FontSize="18" Style="{StaticResource LoginButton}" Canvas.Left="49" Canvas.Top="290" Height="40" Width="116" FontWeight="Bold" Content="{DynamicResource GlobalLableButtonLogin}" IsDefault="True"/>
|
||||
<Button FontSize="20" Style="{StaticResource LoginButton}" Canvas.Left="233" Canvas.Top="290" Click="OnExitClicked" Height="40" Width="116" FontWeight="Bold" Content="{DynamicResource GlobalLableButtonExit}"/>
|
||||
<Label Canvas.Left="135" Height="40" Width="160" Content="{DynamicResource GlobalLableUserLogin}" />
|
||||
<Label Canvas.Left="28" Canvas.Top="224" Content="" Height="40" Name="LabelResult" Width="307" Foreground="White" />
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Window>
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Aitex.Core.Account;
|
||||
using MECF.Framework.UI.Core.Applications;
|
||||
|
||||
namespace MECF.Framework.UI.Core.Accounts
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainLogin.xaml
|
||||
/// </summary>
|
||||
public partial class PasswordMsgBox : Window
|
||||
{
|
||||
PasswordMsgBoxModel viewModel;
|
||||
|
||||
public PasswordMsgBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
viewModel = new PasswordMsgBoxModel();
|
||||
DataContext = viewModel;
|
||||
}
|
||||
|
||||
private string userName = "admin";
|
||||
|
||||
private void OnLoginClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
IntPtr p = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(passwordBox.SecurePassword);
|
||||
string passWord = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(p);
|
||||
viewModel.UserName = userName;
|
||||
viewModel.Password = passWord;
|
||||
LoginResult loginResult = AccountClient.Instance.Service.Login(userName, passWord);
|
||||
|
||||
LabelResult.Content = loginResult.Description;
|
||||
|
||||
if (loginResult.ActSucc)
|
||||
{
|
||||
this.DialogResult = true;
|
||||
this.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.passwordBox.Focus();
|
||||
this.LabelResult.Content = "error in your password. Please re-enter";
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExitClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.DialogResult = false;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
using Aitex.Core.Account;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MECF.Framework.UI.Core.Accounts
|
||||
{
|
||||
public class PasswordMsgBoxModel
|
||||
{
|
||||
private string _userName = "";
|
||||
private string _password = "";
|
||||
|
||||
public string UserName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _userName;
|
||||
}
|
||||
set
|
||||
{
|
||||
_userName = value;
|
||||
}
|
||||
}
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
return _password;
|
||||
}
|
||||
set
|
||||
{
|
||||
_password = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Account AccountInfo
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Token
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Role
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public void SetLoginResult(LoginResult result)
|
||||
{
|
||||
AccountClient.Instance.CurrentUser = result.AccountInfo;
|
||||
AccountInfo = result.AccountInfo;
|
||||
Token = result.Token;
|
||||
Role = AccountInfo.Role;
|
||||
}
|
||||
|
||||
public PasswordMsgBoxModel()
|
||||
{
|
||||
|
||||
|
||||
|
||||
UserName = string.Empty;
|
||||
Password = string.Empty;
|
||||
|
||||
AccountInfo = new Account();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -186,7 +186,7 @@ namespace MECF.Framework.UI.Core.Applications
|
|||
|
||||
if (_instance.EnableAccountModule)
|
||||
{
|
||||
AccountClient.Instance.Service.RegisterViews(_views.GetAllViewList);
|
||||
/*AccountClient.Instance.Service.RegisterViews(_views.GetAllViewList);
|
||||
if (_views.SystemName == "GonaSorterUI")
|
||||
{
|
||||
GonaMainLogin mainLogin = new GonaMainLogin();
|
||||
|
@ -212,7 +212,7 @@ namespace MECF.Framework.UI.Core.Applications
|
|||
_views.SetViewPermission(account);
|
||||
_views.MainWindow.Show();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,20 +114,9 @@
|
|||
<Compile Include="Accounts\CurrentLogInUsers.xaml.cs">
|
||||
<DependentUpon>CurrentLogInUsers.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Accounts\GonaMainLogin.xaml.cs">
|
||||
<DependentUpon>GonaMainLogin.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Accounts\LoginViewModel.cs" />
|
||||
<Compile Include="Accounts\PasswordMsgBox.xaml.cs">
|
||||
<DependentUpon>PasswordMsgBox.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Accounts\MainLogin.xaml.cs">
|
||||
<DependentUpon>MainLogin.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Accounts\MyAccount.xaml.cs">
|
||||
<DependentUpon>MyAccount.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Accounts\PasswordMsgBoxModel.cs" />
|
||||
<Compile Include="Accounts\RoleEditView.xaml.cs">
|
||||
<DependentUpon>RoleEditView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -487,18 +476,6 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Accounts\GonaMainLogin.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Accounts\PasswordMsgBox.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Accounts\MainLogin.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Accounts\MyAccount.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
|
|
@ -91,7 +91,6 @@ Global
|
|||
{EBE55E3F-6DCE-47B9-AC61-54A8B9B3482A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EBE55E3F-6DCE-47B9-AC61-54A8B9B3482A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F619C5AD-D0D9-4758-A85E-D747156709E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F619C5AD-D0D9-4758-A85E-D747156709E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F619C5AD-D0D9-4758-A85E-D747156709E6}.DebugWithoutCopy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F619C5AD-D0D9-4758-A85E-D747156709E6}.DebugWithoutCopy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F619C5AD-D0D9-4758-A85E-D747156709E6}.DebugWithoutCopyFiles|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
|
|
Loading…
Reference in New Issue