আমি বিভিন্ন সমাধান দেখার জন্য অনেক সময় ব্যয় করেছি। আমি সজ্জকারদের ধারণা পছন্দ করি না, আচরণগুলি ভেরিফিকেশন ইউআই, পেছনের কোডটি গণ্ডগোল করে দেয় ... সত্যিই?
এখনও সেরাটি হ'ল একটি কাস্টম সংযুক্ত সম্পত্তিকে আটকে রাখা SecureString
এবং আপনার ভিউ মডেলটিতে আপনার সম্পত্তিটিকে আবদ্ধ করা । আপনি যতক্ষণ পারবেন সেখানে এটি রাখুন। যখনই আপনার সরল পাসওয়ার্ডে দ্রুত অ্যাক্সেসের প্রয়োজন হবে, অস্থায়ীভাবে নীচের কোডটি ব্যবহার করে এটি একটি অনিরাপদ স্ট্রিংয়ে রূপান্তর করুন:
namespace Namespace.Extensions
{
using System;
using System.Runtime.InteropServices;
using System.Security;
/// <summary>
/// Provides unsafe temporary operations on secured strings.
/// </summary>
[SuppressUnmanagedCodeSecurity]
public static class SecureStringExtensions
{
/// <summary>
/// Converts a secured string to an unsecured string.
/// </summary>
public static string ToUnsecuredString(this SecureString secureString)
{
// copy&paste from the internal System.Net.UnsafeNclNativeMethods
IntPtr bstrPtr = IntPtr.Zero;
if (secureString != null)
{
if (secureString.Length != 0)
{
try
{
bstrPtr = Marshal.SecureStringToBSTR(secureString);
return Marshal.PtrToStringBSTR(bstrPtr);
}
finally
{
if (bstrPtr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(bstrPtr);
}
}
}
return string.Empty;
}
/// <summary>
/// Copies the existing instance of a secure string into the destination, clearing the destination beforehand.
/// </summary>
public static void CopyInto(this SecureString source, SecureString destination)
{
destination.Clear();
foreach (var chr in source.ToUnsecuredString())
{
destination.AppendChar(chr);
}
}
/// <summary>
/// Converts an unsecured string to a secured string.
/// </summary>
public static SecureString ToSecuredString(this string plainString)
{
if (string.IsNullOrEmpty(plainString))
{
return new SecureString();
}
SecureString secure = new SecureString();
foreach (char c in plainString)
{
secure.AppendChar(c);
}
return secure;
}
}
}
আপনি জিসিকে আপনার ইউআই উপাদান সংগ্রহ করার অনুমতি দিয়েছেন তা নিশ্চিত করুন, সুতরাং ইভেন্টে ইভেন্টের জন্য একটি স্ট্যাটিক ইভেন্ট হ্যান্ডলার ব্যবহারের তাড়না প্রতিহত PasswordChanged
করুন PasswordBox
। SecurePassword
সম্পত্তিটি সেট আপ করার জন্য নিয়ন্ত্রণটি ইউআই আপডেট করার সময় আমি এমন একটি বিদ্রূপও আবিষ্কার করেছি যে কারণে পাসওয়ার্ডটি অনুলিপি করছি কেনPassword
পরিবর্তে
namespace Namespace.Controls
{
using System.Security;
using System.Windows;
using System.Windows.Controls;
using Namespace.Extensions;
/// <summary>
/// Creates a bindable attached property for the <see cref="PasswordBox.SecurePassword"/> property.
/// </summary>
public static class PasswordBoxHelper
{
// an attached behavior won't work due to view model validation not picking up the right control to adorn
public static readonly DependencyProperty SecurePasswordBindingProperty = DependencyProperty.RegisterAttached(
"SecurePassword",
typeof(SecureString),
typeof(PasswordBoxHelper),
new FrameworkPropertyMetadata(new SecureString(),FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, AttachedPropertyValueChanged)
);
private static readonly DependencyProperty _passwordBindingMarshallerProperty = DependencyProperty.RegisterAttached(
"PasswordBindingMarshaller",
typeof(PasswordBindingMarshaller),
typeof(PasswordBoxHelper),
new PropertyMetadata()
);
public static void SetSecurePassword(PasswordBox element, SecureString secureString)
{
element.SetValue(SecurePasswordBindingProperty, secureString);
}
public static SecureString GetSecurePassword(PasswordBox element)
{
return element.GetValue(SecurePasswordBindingProperty) as SecureString;
}
private static void AttachedPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// we'll need to hook up to one of the element's events
// in order to allow the GC to collect the control, we'll wrap the event handler inside an object living in an attached property
// don't be tempted to use the Unloaded event as that will be fired even when the control is still alive and well (e.g. switching tabs in a tab control)
var passwordBox = (PasswordBox)d;
var bindingMarshaller = passwordBox.GetValue(_passwordBindingMarshallerProperty) as PasswordBindingMarshaller;
if (bindingMarshaller == null)
{
bindingMarshaller = new PasswordBindingMarshaller(passwordBox);
passwordBox.SetValue(_passwordBindingMarshallerProperty, bindingMarshaller);
}
bindingMarshaller.UpdatePasswordBox(e.NewValue as SecureString);
}
/// <summary>
/// Encapsulated event logic
/// </summary>
private class PasswordBindingMarshaller
{
private readonly PasswordBox _passwordBox;
private bool _isMarshalling;
public PasswordBindingMarshaller(PasswordBox passwordBox)
{
_passwordBox = passwordBox;
_passwordBox.PasswordChanged += this.PasswordBoxPasswordChanged;
}
public void UpdatePasswordBox(SecureString newPassword)
{
if (_isMarshalling)
{
return;
}
_isMarshalling = true;
try
{
// setting up the SecuredPassword won't trigger a visual update so we'll have to use the Password property
_passwordBox.Password = newPassword.ToUnsecuredString();
// you may try the statement below, however the benefits are minimal security wise (you still have to extract the unsecured password for copying)
//newPassword.CopyInto(_passwordBox.SecurePassword);
}
finally
{
_isMarshalling = false;
}
}
private void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
{
// copy the password into the attached property
if (_isMarshalling)
{
return;
}
_isMarshalling = true;
try
{
SetSecurePassword(_passwordBox, _passwordBox.SecurePassword.Copy());
}
finally
{
_isMarshalling = false;
}
}
}
}
}
এবং এক্সএএমএল ব্যবহার:
<PasswordBox controls:PasswordBoxHelper.SecurePassword="{Binding LogonPassword, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
ভিউ মডেলটিতে আমার সম্পত্তিটি দেখতে এমন দেখাচ্ছে:
[RequiredSecureString]
public SecureString LogonPassword
{
get
{
return _logonPassword;
}
set
{
_logonPassword = value;
NotifyPropertyChanged(nameof(LogonPassword));
}
}
RequiredSecureString
নিম্নলিখিত যুক্তিবিজ্ঞান আছে শুধুমাত্র একটি সহজ কাস্টম যাচাইকারী হল:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public class RequiredSecureStringAttribute:ValidationAttribute
{
public RequiredSecureStringAttribute()
:base("Field is required")
{
}
public override bool IsValid(object value)
{
return (value as SecureString)?.Length > 0;
}
}
এখানে আপনি এটি আছে। একটি সম্পূর্ণ এবং পরীক্ষিত খাঁটি এমভিভিএম সমাধান।