এমভিভিএমে পাসওয়ার্ডবক্সে কীভাবে আবদ্ধ থাকতে হয়


251

আমি একটি পি বাঁধাই সঙ্গে একটি সমস্যা জুড়ে এসেছি asswordBox। দেখে মনে হচ্ছে এটি সুরক্ষা ঝুঁকিপূর্ণ তবে আমি এমভিভিএম প্যাটার্নটি ব্যবহার করছি তাই আমি এটিকে বাইপাস করতে চাই। আমি এখানে কিছু আকর্ষণীয় কোড পেয়েছি (কেউ এই বা অনুরূপ কিছু ব্যবহার করেছে?)

http://www.wpftutorial.net/PasswordBox.html

এটি প্রযুক্তিগতভাবে দুর্দান্ত দেখায় তবে পাসওয়ার্ড কীভাবে পুনরুদ্ধার করা যায় সে সম্পর্কে আমি অনিশ্চিত।

আমার মূলত আমার LoginViewModelজন্য Usernameএবং এর মধ্যে বৈশিষ্ট্য রয়েছে PasswordUsernameঠিক আছে এবং এটি একটি হিসাবে কাজ করছে TextBox

আমি উপরে বর্ণিত কোডটি ব্যবহার করেছি এবং এটি প্রবেশ করিয়েছি

<PasswordBox ff:PasswordHelper.Attach="True"
    ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>

যখন আমি ছিল PasswordBoxহিসেবে TextBoxএবং Binding Path=Passwordতারপর আমার সম্পত্তি LoginViewModelআপডেট করা হয়েছে।

আমার কোডটি খুব সহজ, মূলত আমার কাছে Commandআমার একটি রয়েছে Button। আমি টিপলে এটিকে CanLoginডাকা হয় এবং যদি এটি সত্য হয় তবে তা কল করে Login
আপনি দেখতে পাচ্ছেন যে আমি আমার সম্পত্তি পরীক্ষা করে দেখছিUsername এখানে যা দুর্দান্ত কাজ করে।

ইন Loginআমার সেবা একটি বরাবর পাঠাতে Usernameএবং Password, Usernameথেকে তথ্য রয়েছে আমার Viewকিন্তু Passwordহয়Null|Empty

private DelegateCommand loginCommand;

public string Username { get; set; }
public string Password { get; set; }


public ICommand LoginCommand
{
    get
    {
        if (loginCommand == null)
        {
            loginCommand = new DelegateCommand(
                Login, CanLogin );
        }
        return loginCommand;
    }
}

private bool CanLogin()
{
    return !string.IsNullOrEmpty(Username);
}

private void Login()
{
    bool result = securityService.IsValidLogin(Username, Password);

    if (result) { }
    else { }
}

আমি এই কি করছি

<TextBox Text="{Binding Path=Username, UpdateSourceTrigger=PropertyChanged}"
         MinWidth="180" />

<PasswordBox ff:PasswordHelper.Attach="True" 
             ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>

আমার আমার TextBox, এটি কোনও সমস্যা নয়, তবে আমার ViewModelমধ্যে Passwordখালি রয়েছে।

আমি কি কিছু ভুল করছি বা একটি পদক্ষেপ মিস করছি?

আমি একটি ব্রেকপয়েন্ট রেখেছি এবং নিশ্চিতভাবেই কোডটি স্থির সহায়ক সহায়ক শ্রেণিতে প্রবেশ করে তবে এটি আমার Passwordক্ষেত্রে কখনই আপডেট হয় না ViewModel


3
ঠিক আছে এটি কোডটি কাজ করে না তবে আমি এখানে একটি বিকল্প কোড চেষ্টা করেছি এবং এটি পুরোপুরি কার্যকরভাবে কাজ করে। blog.functionalfun.net/2008/06/…
স্মিথ

5
পুরো পাসওয়ার্ডবক্স নিয়ন্ত্রণে পাস করা ভিউ মডেল থেকে ভিউকে আলাদা করার বিরুদ্ধে যায় না?

উত্তর:


164

দুঃখিত, কিন্তু আপনি এটি ভুল করছেন।

লোকেদের তাদের চোখের পাতাগুলির অভ্যন্তরে উল্লিখিত সুরক্ষা নির্দেশিকা থাকা উচিত:
কখনও কখনও সরল পাঠ্য পাসওয়ার্ডগুলিকে মেমরির মধ্যে রাখবেন না।

সম্পত্তির PasswordBoxজন্য ডাব্লুপিএফ / সিলভারলাইট কোনও ডিপি প্রকাশ না করার কারণটি Passwordসুরক্ষা সম্পর্কিত।
ডাব্লুপিএফ / সিলভারলাইটের জন্য যদি কোনও ডিপি Passwordরাখা হয় তবে পাসওয়ার্ডটি মেমরিতে নিজেই এনক্রিপ্ট না করে রাখা কাঠামোর প্রয়োজন would যা বেশ ঝামেলার সুরক্ষা আক্রমণ ভেক্টর হিসাবে বিবেচিত হয়। PasswordBoxব্যবহারসমূহ এনক্রিপ্ট মেমরি (প্রকারের) এবং পাসওয়ার্ড অ্যাক্সেস করার একমাত্র উপায় CLR সম্পত্তি মাধ্যমে হয়।

আমি পরামর্শ দেব যে PasswordBox.Passwordসিএলআর সম্পত্তি অ্যাক্সেস করার সময় আপনি এটিকে কোনও পরিবর্তনশীল বা কোনও সম্পত্তির মান হিসাবে স্থাপন করা থেকে বিরত থাকবেন ।
ক্লায়েন্ট মেশিন র‍্যামে আপনার পাসওয়ার্ডটি সরল পাঠ্যে রাখা কোনও সুরক্ষা নম্বর।
সুতরাং এটি পরিত্রাণ পেতেpublic string Password { get; set; } আপনি সেখানে উঠে ।

অ্যাক্সেস করার সময় PasswordBox.Password, কেবল এটিকে বের করুন এবং এটি ASAP সার্ভারে প্রেরণ করুন। পাসওয়ার্ডের মানটিকে চারপাশে রাখবেন না এবং এটির মতো ব্যবহার করবেন না যেমন আপনি অন্য কোনও ক্লায়েন্ট মেশিন পাঠ্য। স্পষ্ট পাঠ্যের পাসওয়ার্ডগুলি মেমরিতে রাখবেন না।

আমি জানি এটি এমভিভিএম প্যাটার্নটি ভেঙে ফেলেছে তবে আপনার কখনও বাঁধা থাকা উচিত নয় PasswordBox.Password সংযুক্ত ডিপির , আপনার পাসওয়ার্ড ভিউমোডেল বা অন্য কোনও অনুরূপ শেননিগানে সংরক্ষণ করতে হবে।

আপনি যদি কোনও অতি-আর্কিটেটেড সমাধানের সন্ধান করে থাকেন তবে এখানে একটি: এখানে একটি পদ্ধতি দিয়ে ইন্টারফেস
তৈরি করুন IHavePasswordযা পাসওয়ার্ডের স্বচ্ছ পাঠ্য ফেরত দেয়।
২. আপনার ইন্টারফেস UserControlপ্রয়োগ IHavePasswordকরুন।
৩. UserControlআপনার আইওসির সাথে IHavePasswordইন্টারফেসটি বাস্তবায়ন হিসাবে উদাহরণটি নিবন্ধ করুন।
৪. যখন আপনার পাসওয়ার্ডের জন্য কোনও সার্ভারের অনুরোধ চলছে, তখন IHavePasswordপ্রয়োগের জন্য আপনার আইওসি-তে কল করুন এবং কেবলমাত্র লোভনীয় পাসওয়ার্ড না পেয়ে।

এটা আমার গ্রহণ।

- জাস্টিন


19
আপনি কি এই সমস্যার সমাধানের জন্য ডাব্লুপিএফ এর জন্য ভিএম-এ সিকিউরস্ট্রিং ব্যবহার করতে পারবেন না? সিলভারলাইটের জন্য কিছু আছে বলে মনে হয় না।
ব্রায়ান্ট

35
আমি আপনার উদ্দেশ্য এবং আপনি যে বার্তাটি দিচ্ছেন তার সাথে আমি একমত আছি তবে আপনার উত্তর থেকে বোঝা যাচ্ছে যে আপনি যদি এই পদ্ধতির অনুসরণ করেন তবে পাসওয়ার্ডের স্ট্রিং কখনই স্মরণে থাকে না। পাসওয়ার্ডটির মান ব্যবহারকারীর টাইপ করার মুহুর্ত থেকেই এটি স্মৃতিতে থাকবে। আপনার পাসফ্রেজ সম্বলিত সম্পত্তি হ্রাস করা একটি ভাল ধারণা এবং এটি আপনার পাসওয়ার্ডের অনুলিপিগুলিকে সীমাবদ্ধ রাখবে যা আবর্জনা সংগ্রহকারীকে কাটা কাটা পড়ে বা এটি সম্ভবত আপনার প্রোগ্রামের অংশ হিসাবে চালিত অন্যান্য পরিচালিত এবং পরিচালনা ব্যবস্থা দ্বারা পাওয়া যেতে পারে, তবে এটি পুরোপুরি আড়াল না।
ইয়াননরটন

182
বেশিরভাগ ক্ষেত্রেই, আপনি না নিরাপত্তার যে স্তর প্রয়োজন। পাসওয়ার্ড চুরি করার আরও অনেক উপায় থাকলেও সেই জিনিসটিকে শক্ত করার কী দরকার? কমপক্ষে ডাব্লুপিএফকে @ ব্রায়ান্টের মতো সিকিউরস্ট্রিং ব্যবহারের অনুমতি দেওয়া উচিত ছিল।
চক্রটি

335
খারাপ লোকদের যদি আপনার মেশিনের র‍্যামে অ্যাক্সেস থাকে তবে আপনার পাসওয়ার্ড চুরি করার চেয়ে আপনার কাছে আরও বড় সমস্যা রয়েছে।
ক্যামেরন ম্যাকফারল্যান্ড

13
কয়েক বছর ধরে, আমি একটি কাস্টম ব্যবহারকারী নিয়ন্ত্রণ ব্যবহার করছি যা পাসওয়ার্ডবক্সের মতো আচরণ করে, তবে কেবলমাত্র সিকিউরস্ট্রিং হিসাবে পাঠ্য মানটি দেয়। হ্যাঁ, এটি স্নুপকে সরল পাঠ্যে পাসওয়ার্ড প্রদর্শন করতে বাধা দেয়। তবে সিকিউরস্ট্রিংয়ের সরল পাঠ্য মানটি এখনও বেশ সহজেই বের করা যেতে পারে এবং কেবল নবীন হ্যাকদেরই ডিটার্স করে। যদি আপনার সিস্টেমে গোপনে কী লগার এবং স্নুপের মতো স্নিফার নিয়োগের ঝুঁকি থাকে তবে আপনার সিস্টেমের সুরক্ষায় আপনার পুনরায় মূল্যায়ন করা উচিত।
মাইক খ্রিস্টান

199

আমার 2 সেন্ট:

আমি একবার ডাব্লুপিএফ এবং এমভিভিএম ব্যবহার করে একটি সাধারণ লগইন ডায়লগ (ব্যবহারকারী এবং পাসওয়ার্ড বাক্স, এবং "ঠিক আছে" বোতাম) তৈরি করেছি। আমি পাসওয়ার্ড বাইন্ডিংয়ের সমস্যাটিকে কেবল "ওকে" বোতামের সাথে সংযুক্ত কমান্ডের প্যারামিটার হিসাবে পাসওয়ার্ডবক্স নিয়ন্ত্রণ করেই সমাধান করেছি। সুতরাং আমার মতামত:

<PasswordBox Name="txtPassword" VerticalAlignment="Top" Width="120" />
<Button Content="Ok" Command="{Binding Path=OkCommand}"
   CommandParameter="{Binding ElementName=txtPassword}"/>

এবং ভিউমোডেলে, Executeসংযুক্ত কমান্ডের পদ্ধতিটি নিম্নরূপ ছিল:

void Execute(object parameter)
{
    var passwordBox = parameter as PasswordBox;
    var password = passwordBox.Password;
    //Now go ahead and check the user name and password
}

এটি সামান্য কিছুটা এমভিভিএম প্যাটার্নটিকে লঙ্ঘন করে এখন থেকে ভিউমোডেল কীভাবে ভিউ বাস্তবায়িত হয় সে সম্পর্কে কিছু জানে তবে সেই নির্দিষ্ট প্রকল্পে আমি এটি বহন করতে পারতাম। আশা করি এটি কারওর জন্যও কার্যকর।


হ্যালো কোনামিমন, যখন এক্সিকিউট পদ্ধতিটি বলা হয় my আমার ভিউ মডেলটিতে আমার একটি ক্লাস ব্যবহারকারী (লগইন, পাস) এবং একটি কমান্ড প্রমাণীকরণ রয়েছে that সেই প্রসঙ্গে আমি কীভাবে এক্সিকিউট ব্যবহার করতে পারি?

3
অনেক সহায়ক, ধন্যবাদ সুতরাং, কেউ _ লগিনকম্যান্ড = নতুন রিলে কম্যান্ড (প্যারাম => লগইন (ব্যবহারকারীর নাম, (পাসওয়ার্ডবক্স) পরম), প্যারাম => ক্যানলগআইএন) এর মতো কিছু দেখার জন্য অভ্যস্ত হতে পারে;
চাক রোস্ট্যান্স

5
এটি একটি ঠিক সমাধান তবে পাসওয়ার্ড + পাসওয়ার্ড কনফার্মেশন কম্বোর মতো কিছুতে ব্যর্থ
জুলিয়েন

হ্যালো কোনামিমন, আমি আপনার সমাধানটি ব্যবহার করছি তবে এটি উইন্ডোজ 8.1 স্টোর অ্যাপ্লিকেশনটিতে কাজ করে না। : আমি এই প্রশ্ন জিজ্ঞাসা করে থাকেন stackoverflow.com/questions/26221594/...
VansFannel

2
এর জন্য ধন্যবাদ! এটি ইউআই থ্রেড থেকে মূল প্রোগ্রামের থ্রেডে ডেটা স্থানান্তরিত করার সাথে আমার একটি বিশাল সমস্যার সমাধান হয়েছিল। সিকিউরস্ট্রিং পদ্ধতির বাস্তবায়ন নিশ্চিত করুন এবং as যত তাড়াতাড়ি সম্ভব পাসওয়ার্ড থেকে মুক্তি পান ~ ফেলে দাও। এটি নিষ্পত্তি করুন। এটি সাফ করুন। আপনাকে যা করতে হবে তা না। এছাড়াও, আপনি IDisposable বাস্তবায়ন নিশ্চিত করুন।
স্টিভেন সি। ব্রিটন

184

হতে পারে আমি কিছু মিস করছি, তবে এটি বেশিরভাগ সমাধানের মতো মনে হয় জটিল জিনিসগুলিকে জটিল করে তোলে এবং সুরক্ষিত অনুশীলনগুলি দিয়ে যায়।

এই পদ্ধতিটি এমভিভিএম প্যাটার্ন লঙ্ঘন করে না এবং সম্পূর্ণ সুরক্ষা বজায় রাখে। হ্যাঁ, প্রযুক্তিগতভাবে এটি পিছনের কোড, তবে এটি "বিশেষ কেস" বাইন্ডিং ছাড়া আর কিছুই নয়। ভিউমোডেলটিতে এখনও ভিউ বাস্তবায়নের কোনও জ্ঞান নেই, যা আপনি যদি মনমুখে পাসওয়ার্ডবক্সকে ভিউমোডলে পাস করার চেষ্টা করছেন তবে তা আমার মনে এটি করে।

পিছনে কোড! = স্বয়ংক্রিয় এমভিভিএম লঙ্ঘন। এটি আপনার সাথে কী করবেন তার উপর নির্ভর করে। এই ক্ষেত্রে, আমরা ম্যানুয়ালি একটি বাঁধাই কোডিং করছি, সুতরাং এটি ইউআই বাস্তবায়ন অংশ হিসাবে বিবেচিত এবং তাই ঠিক আছে।

ভিউমোডেলে, কেবল একটি সাধারণ সম্পত্তি। আমি এটিকে "কেবল লিখতে" তৈরি করেছি যেহেতু কোনও কারণে ভিউমোডেলের বাইরে থেকে এটি পুনরুদ্ধার করার দরকার নেই, তবে এটি হওয়ার দরকার নেই। মনে রাখবেন এটি কেবল একটি স্ট্রিং নয়, একটি সিকিওরস্ট্রিং।

public SecureString SecurePassword { private get; set; }

এক্সএএমএলে, আপনি একটি পাসওয়ার্ড চেঞ্জড ইভেন্ট হ্যান্ডলার সেটআপ করেছেন।

<PasswordBox PasswordChanged="PasswordBox_PasswordChanged"/>

পিছনে কোডে:

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
    if (this.DataContext != null)
    { ((dynamic)this.DataContext).SecurePassword = ((PasswordBox)sender).SecurePassword; }
}

এই পদ্ধতির সাহায্যে আপনার পাসওয়ার্ডটি সর্বদা একটি সিকিউরস্ট্রিংয়ে থাকে এবং তাই সর্বাধিক সুরক্ষা সরবরাহ করে। আপনি যদি সুরক্ষার বিষয়ে সত্যই চিন্তা করেন না বা ডাউন স্ট্রিম পদ্ধতির জন্য এটির জন্য আপনার স্পষ্ট পাঠ্য পাসওয়ার্ডের প্রয়োজন হয় (দ্রষ্টব্য: সর্বাধিক। নেট পদ্ধতিতে যে পাসওয়ার্ডের প্রয়োজন হয় সেগুলিও একটি সিকিউরস্ট্রিং বিকল্প সমর্থন করে, সুতরাং আপনার প্রকৃতপক্ষে কোনও স্পষ্ট পাঠ্য পাসওয়ার্ডের প্রয়োজন পড়বে না এমনকি যদি আপনি ভাবেন যে আপনি এটি করেন) তবে আপনি কেবল এর পরিবর্তে পাসওয়ার্ডের সম্পত্তিটি ব্যবহার করতে পারেন। এটার মত:

(ভিডমোডেল সম্পত্তি)

public string Password { private get; set; }

(পিছনে কোড)

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
    if (this.DataContext != null)
    { ((dynamic)this.DataContext).Password = ((PasswordBox)sender).Password; }
}

আপনি যদি জিনিসগুলিকে দৃ strongly়ভাবে টাইপ করতে চান তবে আপনি নিজের ভিউমোডেলের ইন্টারফেসের সাথে (ডায়নামিক) কাস্টটি বিকল্পযুক্ত করতে পারেন। তবে সত্যই, "সাধারণ" ডেটা বাইন্ডিংগুলি শক্তভাবে টাইপ করা হয় না, তাই এটি এত বড় চুক্তি নয়।

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
    if (this.DataContext != null)
    { ((IMyViewModel)this.DataContext).Password = ((PasswordBox)sender).Password; }
}

সুতরাং সমস্ত পৃথিবীর সেরা - আপনার পাসওয়ার্ডটি সুরক্ষিত, আপনার ভিউমোডেলটিতে অন্য যে কোনও সম্পত্তির মতোই একটি সম্পত্তি রয়েছে এবং আপনার ভিউটিতে কোনও বাহ্যিক উল্লেখের প্রয়োজন নেই self


1
এই আমার ভাল লাগছে! আপনি যদি সুরক্ষা পক্ষের উপর কঠোর হতে চান তবে নিশ্চিত যে এটি এটি কেটে ফেলবে, তবে আমার কাছে এটি একটি নিখুঁত মাঝারি ক্ষেত্র। ধন্যবাদ!
jrich523

3
এমভিভিএম এবং ভৌগলিকতা সম্পর্কে কঠোর মতবাদ সম্পর্কে বাস্তবতার জন্য ধন্যবাদ। ধন্যবাদ দুর্দান্ত কাজ করে
ব্রুস পাইর্সন

2
সিকিউরস্ট্রিং উদাহরণটি এই এক্সটেনশনের সাথে দুর্দান্ত হবে ব্লগস.এমএসএনএন
আইমান

1
সত্যিই দুর্দান্ত। আমি আশা করি এমএস এই নিয়ন্ত্রণে সিকিউরস্ট্রিং টাইপের একটি পাসওয়ার্ড ডিপি যুক্ত করত।
কিথ হিল 17

1
এটি নির্ভুল উত্তর, কারণ এটি সুরক্ষা এবং এমভিভিএম রাখে।
LoRdPMN

20

আপনি এই এক্সএএমএল ব্যবহার করতে পারেন:

<PasswordBox Name="PasswordBox">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="PasswordChanged">
            <i:InvokeCommandAction Command="{Binding PasswordChangedCommand}" CommandParameter="{Binding ElementName=PasswordBox}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</PasswordBox>

এবং এই আদেশটি কার্যকর পদ্ধতি:

private void ExecutePasswordChangedCommand(PasswordBox obj)
{ 
   if (obj != null)
     Password = obj.Password;
}

3
এফওয়াইআইxmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
এক্সএএমএলএমএক্স

একটি পাসওয়ার্ডবক্সের নাম ছাড়াই: CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=PasswordBox}}"(নোট: নয় RelativeSource Self )।
আশ্চর্য

এই সমাধানটি এমভিভিএম প্যাটার্ন লঙ্ঘন করে।
বায়োনিক কোড

13

এটি আমার পক্ষে ঠিক কাজ করে।

<Button Command="{Binding Connect}" 
        CommandParameter="{Binding ElementName=MyPasswordBox}"/>

3
কমান্ডপ্যারামিটার = "{বাইন্ডিং এলিমেন্টনাম = মাইপ্যাসওয়ার্ডবক্স, পাথ = সিকিউরপ্যাসওয়ার্ড" about?
লুক

2
লুকএন, এটি কাজ করে না (কমপক্ষে আমার জন্য)। সম্ভবত একই কারণে - সিকিউরপাসওয়ার্ড নির্ভরতা সম্পত্তি নয়।
vkrzv

ICommandএই ধারণাটি মডেলটিতে প্রয়োগ করা হয়েছে বলে ধরে নেওয়া , এই সমাধানটি এমভিভিএম প্যাটার্ন লঙ্ঘন করবে।
বায়োনিক কোড

9

এমভিভিএম প্যাটার্নটি লঙ্ঘন না করে একটি সহজ সমাধানটি ভিউমোডেলে এমন একটি ইভেন্ট (বা প্রতিনিধি) প্রবর্তন করা যা পাসওয়ার্ডটি কাটা করে।

ইন ViewModel :

public event EventHandler<HarvestPasswordEventArgs> HarvestPassword;

এই ইভেন্টআর্গ সহ:

class HarvestPasswordEventArgs : EventArgs
{
    public string Password;
}

মধ্যে দেখুন , পাসওয়ার্ড মান ViewModel এবং ভরাট তৈরির ঘটনা সাবস্ক্রাইব।

_viewModel.HarvestPassword += (sender, args) => 
    args.Password = passwordBox1.Password;

ইন ViewModel , যখন আপনি পাসওয়ার্ড, আপনি ঘটনা ফায়ার এবং সেখান থেকে পাসওয়ার্ড ফসল করতে পারেন:

if (HarvestPassword == null)
  //bah 
  return;

var pwargs = new HarvestPasswordEventArgs();
HarvestPassword(this, pwargs);

LoginHelpers.Login(Username, pwargs.Password);

আপনি যে জিনিসটি মিস করছেন তা হ'ল কোনও ভিউ মডেল ইভেন্টে ভিউ সাবস্ক্রাইব করার সময়, WeakEventManager<TEventSource, TEventArgs>মেমরি ফাঁস এড়াতে আপনার ব্যবহার করা উচিত । প্রায়শই বার দেখা ভিউমোডেলের মতো আজীবন থাকে না। WeakEventManager<IViewModel, EventArgs>.AddHandler(iViewModelInstance, nameof(IViewModel.Event), eventHandlerMethod);
টড এ। স্টেদেল

আমি এই সমাধানটি পছন্দ করি, কারণ এটি সহজ, এমভিভিএম লঙ্ঘন করে না, পিছনে ন্যূনতম কোড রয়েছে, পাসওয়ার্ডবক্সের সঠিক ব্যবহারের অনুমতি দেয় (যদি আপনি পরিবর্তে ecSecurePassword´ ব্যবহার করেন)। এছাড়াও এখন অন্যান্য হার্ভেস্টপ্যাসওয়ার্ড পদ্ধতি বাস্তবায়নের পক্ষে এখনই সহজ (স্মার্টকার্ডের মতো ....)
ম্যাট

8

আমি বিভিন্ন সমাধান দেখার জন্য অনেক সময় ব্যয় করেছি। আমি সজ্জকারদের ধারণা পছন্দ করি না, আচরণগুলি ভেরিফিকেশন ইউআই, পেছনের কোডটি গণ্ডগোল করে দেয় ... সত্যিই?

এখনও সেরাটি হ'ল একটি কাস্টম সংযুক্ত সম্পত্তিকে আটকে রাখা 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করুন PasswordBoxSecurePasswordসম্পত্তিটি সেট আপ করার জন্য নিয়ন্ত্রণটি ইউআই আপডেট করার সময় আমি এমন একটি বিদ্রূপও আবিষ্কার করেছি যে কারণে পাসওয়ার্ডটি অনুলিপি করছি কেন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;
    }
}

এখানে আপনি এটি আছে। একটি সম্পূর্ণ এবং পরীক্ষিত খাঁটি এমভিভিএম সমাধান।


7

আমি এখানে একটি জিআইএসটি পোস্ট করেছি যা একটি বাইন্ডেবল পাসওয়ার্ড বাক্স।

using System.Windows;
using System.Windows.Controls;

namespace CustomControl
{
    public class BindablePasswordBox : Decorator
    {
        /// <summary>
        /// The password dependency property.
        /// </summary>
        public static readonly DependencyProperty PasswordProperty;

        private bool isPreventCallback;
        private RoutedEventHandler savedCallback;

        /// <summary>
        /// Static constructor to initialize the dependency properties.
        /// </summary>
        static BindablePasswordBox()
        {
            PasswordProperty = DependencyProperty.Register(
                "Password",
                typeof(string),
                typeof(BindablePasswordBox),
                new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnPasswordPropertyChanged))
            );
        }

        /// <summary>
        /// Saves the password changed callback and sets the child element to the password box.
        /// </summary>
        public BindablePasswordBox()
        {
            savedCallback = HandlePasswordChanged;

            PasswordBox passwordBox = new PasswordBox();
            passwordBox.PasswordChanged += savedCallback;
            Child = passwordBox;
        }

        /// <summary>
        /// The password dependency property.
        /// </summary>
        public string Password
        {
            get { return GetValue(PasswordProperty) as string; }
            set { SetValue(PasswordProperty, value); }
        }

        /// <summary>
        /// Handles changes to the password dependency property.
        /// </summary>
        /// <param name="d">the dependency object</param>
        /// <param name="eventArgs">the event args</param>
        private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs eventArgs)
        {
            BindablePasswordBox bindablePasswordBox = (BindablePasswordBox) d;
            PasswordBox passwordBox = (PasswordBox) bindablePasswordBox.Child;

            if (bindablePasswordBox.isPreventCallback)
            {
                return;
            }

            passwordBox.PasswordChanged -= bindablePasswordBox.savedCallback;
            passwordBox.Password = (eventArgs.NewValue != null) ? eventArgs.NewValue.ToString() : "";
            passwordBox.PasswordChanged += bindablePasswordBox.savedCallback;
        }

        /// <summary>
        /// Handles the password changed event.
        /// </summary>
        /// <param name="sender">the sender</param>
        /// <param name="eventArgs">the event args</param>
        private void HandlePasswordChanged(object sender, RoutedEventArgs eventArgs)
        {
            PasswordBox passwordBox = (PasswordBox) sender;

            isPreventCallback = true;
            Password = passwordBox.Password;
            isPreventCallback = false;
        }
    }
}

1
এটি খারাপ না হলেও আপনি প্যাডিং এবং ট্যাবিনডেক্সের মতো সাধারণ বৈশিষ্ট্যগুলি নির্ধারণের ক্ষমতা হারাবেন
জুলিয়েন

1
টেলর, আমি সারাংশটি ইঙ্গিত করেছিলাম যাতে এটি উত্তরটিতে পাওয়া যায়। (এটি অন্যথায় কোনও লিঙ্ক-কেবল উত্তরের মতো দেখছিল .. কেবল এটিকে মুছে ফেলা এড়াতে চাইছিল)) অন্তর্ভুক্ত বিষয়বস্তুতে দ্বিধা বোধ করবেন না।
লিন ক্রম্বলিং

@ জুলিয়েন তবে আপনি শৈলীর সাথে এটি ঠিক করতে পারেন। আমি এই সমস্যাটিকে একইভাবে সমাধান করি তবে আমি এমন একটি ব্যবহার করি যা ContentControlআপনি কেবলমাত্র একটি পাসওয়ার্ডবক্সকে আপনার সামগ্রী অনুসারে এক্সএএমএল-তে থাকা সামগ্রী এবং স্টাইল হিসাবে ব্যবহার করতে পারেন। এর উদ্দেশ্যটি ContentControlহ'ল PasswordChangedইভেন্টটির সাবস্ক্রাইব করা এবং দ্বি-দিকনির্দেশনামূলক বাইন্ডেবল সম্পত্তি প্রকাশ করা। সব মিলিয়ে, এটি কোডের 65 টি লাইন এবং প্রায় এই সজ্জিত শ্রেণিটি কি করে। নিম্নলিখিত আমার সারকথা জন্য এখানে দেখুন gist.github.com/leidegre/c7343b8c720000fe3132
জন Leidegren

6

এই বাস্তবায়ন কিছুটা আলাদা। আপনি ভিউমোডেলে কোনও সম্পত্তি বাঁধার মাধ্যমে একটি পাসওয়ার্ডবক্সটি পাস করেন, এটি কোনও কমান্ড প্যারাম ব্যবহার করে না। দ্য ভিউমোডেল দৃশ্যটি উপেক্ষা করে। আমার কাছে একটি ভিবি বনাম 2010 প্রকল্প রয়েছে যা স্কাইড্রাইভ থেকে ডাউনলোড করা যেতে পারে। ডাব্লুপিএফ এমভিভিএম পাসওয়ার্ডবক্স উদাহরণ.জিপ https://skydrive.live.com/redir.aspx?cid=e95997d33a9f8d73&resid=E95997D33A9F8D73!511

আমি ডাব্লুপিএফ এমভিভিএম অ্যাপ্লিকেশনটিতে যেভাবে পাসওয়ার্ডবক্স ব্যবহার করছি তা বেশ সরল এবং আমার পক্ষে ভালভাবে কাজ করে। এর অর্থ এই নয় যে আমি মনে করি এটি সঠিক উপায় বা সেরা উপায়। এটি কেবল পাসওয়ার্ডবক্স এবং এমভিভিএম প্যাটার্ন ব্যবহারের একটি বাস্তবায়ন।

মূলত আপনি একটি সর্বজনীন পঠনযোগ্য সম্পত্তি তৈরি করেন যা ভিউ একটি পাসওয়ার্ডবক্স হিসাবে আবশ্যক (প্রকৃত নিয়ন্ত্রণ) উদাহরণ:

Private _thePassWordBox As PasswordBox
Public ReadOnly Property ThePassWordBox As PasswordBox
    Get
        If IsNothing(_thePassWordBox) Then _thePassWordBox = New PasswordBox
        Return _thePassWordBox
    End Get
End Property

আমি কেবল সম্পত্তির স্বাবলম্বকরণ করতে একটি ব্যাকিং ফিল্ড ব্যবহার করি।

তারপরে Xaml থেকে আপনি একটি সামগ্রীর নিয়ন্ত্রণের সামগ্রী বা একটি নিয়ন্ত্রণ পাত্রে উদাহরণকে আবদ্ধ করুন:

 <ContentControl Grid.Column="1" Grid.Row="1" Height="23" Width="120" Content="{Binding Path=ThePassWordBox}" HorizontalAlignment="Center" VerticalAlignment="Center" />

সেখান থেকে আপনার পাসওয়ার্ডবক্সের পুরো নিয়ন্ত্রণ রয়েছে আমি লগইন করার সময় পাসওয়ার্ড মানটি ফিরিয়ে দিতে বা পাসওয়ার্ডের জন্য যা চাইবে অন্য কোনও পাসওয়ার্ডএকসেসর (স্ট্রিংয়ের কেবলমাত্র একটি ফাংশন) ব্যবহার করি। উদাহরণে আমার কাছে একটি জেনেরিক ব্যবহারকারী অবজেক্ট মডেলটিতে একটি সর্বজনীন সম্পত্তি রয়েছে। উদাহরণ:

Public Property PasswordAccessor() As Func(Of String)

ইউজার অবজেক্টে পাসওয়ার্ড স্ট্রিংয়ের সম্পত্তিটি কোনও ব্যাকিং স্টোর ছাড়াই পঠনযোগ্য এটি কেবল পাসওয়ার্ডবক্স থেকে পাসওয়ার্ড ফেরত দেয়। উদাহরণ:

Public ReadOnly Property PassWord As String
    Get
        Return If((PasswordAccessor Is Nothing), String.Empty, PasswordAccessor.Invoke())
    End Get
End Property

তারপরে ভিউমোডেলে আমি নিশ্চিত করে নিই যে অ্যাকসেসর তৈরি হয়েছে এবং পাসওয়ার্ডবক্সে সেট করা হয়েছে। পাসওয়ার্ডের সম্পত্তি 'উদাহরণ:

Public Sub New()
    'Sets the Accessor for the Password Property
    SetPasswordAccessor(Function() ThePassWordBox.Password)
End Sub

Friend Sub SetPasswordAccessor(ByVal accessor As Func(Of String))
    If Not IsNothing(VMUser) Then VMUser.PasswordAccessor = accessor
End Sub

লগইন করার জন্য আমার যখন পাসওয়ার্ড স্ট্রিংয়ের প্রয়োজন হবে তখন আমি কেবলমাত্র ইউজার অবজেক্টস পাসওয়ার্ডের সম্পত্তিটি পাই যা সত্যিই পাসওয়ার্ডটি হস্তান্তর করতে এবং এটি ফিরিয়ে দেওয়ার জন্য ফাংশনটিকে অনুরোধ করে, তবে প্রকৃত পাসওয়ার্ডটি ব্যবহারকারী অবজেক্ট দ্বারা সংরক্ষণ করা হয় না। উদাহরণ: ভিউমোডেলে থাকবে

Private Function LogIn() as Boolean
    'Make call to your Authentication methods and or functions. I usally place that code in the Model
    Return AuthenticationManager.Login(New UserIdentity(User.UserName, User.Password)
End Function

যা করা উচিৎ. ViewModel এর দেখার নিয়ন্ত্রণগুলির কোনও জ্ঞানের প্রয়োজন নেই। ভিউটি কেবলমাত্র ভিউমোডেলে সম্পত্তির সাথে আবদ্ধ হয়, কোনও চিত্র বা অন্যান্য সংস্থানকে ভিউ বাইন্ডিংয়ের চেয়ে আলাদা নয়। এক্ষেত্রে সেই সংস্থান (সম্পত্তি) কেবল একজন ব্যবহারকারী নিয়ন্ত্রণকারী হিসাবে ঘটে। ভিউমোডেল যেমন সম্পত্তি তৈরি করে এবং তার মালিকানা দেয় তেমনি পরীক্ষার অনুমতি দেয় এবং সম্পত্তিটি ভিউ থেকে স্বতন্ত্র। সুরক্ষা হিসাবে আমি জানি না এই বাস্তবায়নটি কতটা ভাল। তবে একটি ফাংশন ব্যবহার করে মানটি কেবল সম্পত্তি দ্বারা অ্যাক্সেস করা সম্পত্তিটিতে সংরক্ষণ করা হয় না।


6

এমভিভিএমটি না ভেঙে ওপি সমস্যা সমাধানের জন্য, আমি পাসওয়ার্ড বাক্স থেকে প্রাপ্ত মান (পাসওয়ার্ড) এর জন্য কাস্টম মান রূপান্তরকারী এবং একটি মোড়ক ব্যবহার করব।

public interface IWrappedParameter<T>
{
    T Value { get; }
}

public class PasswordBoxWrapper : IWrappedParameter<string>
{
    private readonly PasswordBox _source;

    public string Value
    {
        get { return _source != null ? _source.Password : string.Empty; }
    }

    public PasswordBoxWrapper(PasswordBox source)
    {
        _source = source;
    }
}

public class PasswordBoxConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Implement type and value check here...
        return new PasswordBoxWrapper((PasswordBox)value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new InvalidOperationException("No conversion.");
    }
}

ভিউ মডেলে:

public string Username { get; set; }

public ICommand LoginCommand
{
    get
    {
        return new RelayCommand<IWrappedParameter<string>>(password => { Login(Username, password); });
    }
}

private void Login(string username, string password)
{
    // Perform login here...
}

যেহেতু ভিউ মডেলটি ব্যবহার করে IWrappedParameter<T>, এটি সম্পর্কেও কোনও জ্ঞানের প্রয়োজন PasswordBoxWrapperনেই PasswordBoxConverter। এইভাবে আপনি বিচ্ছিন্ন করতে পারেনPasswordBox ভিউ মডেল থেকে অবজেক্টটি এবং এমভিভিএম প্যাটার্নটি ভঙ্গ করতে পারবেন না।

দেখুন মধ্যে:

<Window.Resources>
    <h:PasswordBoxConverter x:Key="PwdConverter" />
</Window.Resources>
...
<PasswordBox Name="PwdBox" />
<Button Content="Login" Command="{Binding LoginCommand}"
        CommandParameter="{Binding ElementName=PwdBox, Converter={StaticResource PwdConverter}}" />

খুব মার্জিত সমাধান ইমো। আমি আমার উপর ভিত্তি করে আছে। পার্থক্যটি: আমি স্ট্রিং পাসওয়ার্ডের পরিবর্তে সিকিউরস্ট্রিং সিকিওরপ্যাসওয়ার্ডটি লগইন ফাংশনে পাস করি। যাতে পাসওয়ার্টের মেমরির চারপাশে উড়ন্ত সহ কোনও এনক্রিপ্ট করা স্ট্রিং না থাকে।
আমাকে গাজর বলুন

এটি একটি সময় হয়ে গেছে তবে আমার রিলে কম্যান্ডের কারণে আমি এটি কাজ করতে পারি না বলে মনে হচ্ছে। আপনার নিজের যুক্ত করতে আপত্তি আছে?
ইকনরওয়াল

5

আমি যেহেতু পাসওয়ার্ডটি কোথাও সংরক্ষণ না করা এটি গুরুত্বপূর্ণ বলে সম্মত হয়েছি, তবুও আমার দৃষ্টিভঙ্গি ছাড়াই দর্শন মডেলটি ইনস্ট্যান্ট করার এবং তার বিরুদ্ধে আমার পরীক্ষা চালানোর দক্ষতা প্রয়োজন।

আমার জন্য যে সমাধানটি কাজ করেছিল তা হ'ল ভিউ মডেলের সাথে পাসওয়ার্ডবক্স.প্যাসওয়ার্ড ফাংশনটি নিবন্ধন করা এবং লগইন কোডটি সম্পাদন করার সময় ভিউ মডেলটিকে অনুরোধ করা উচিত।

এই করে দৃশ্য এর codebehind কোড একটি লাইন মানে।

সুতরাং, আমার লগইন.এক্স্যামেল-এ আমার আছে

<PasswordBox x:Name="PasswordBox"/>

এবং login.xaml.cs এ আমার আছে

LoginViewModel.PasswordHandler = () => PasswordBox.Password;

তারপরে লগইনভিউমোডেল.cs এ আমার পাসওয়ার্ডহ্যান্ডলার সংজ্ঞায়িত হয়েছে

public Func<string> PasswordHandler { get; set; }

এবং যখন লগইন হওয়ার দরকার হয় তখন কোডটি পাসওয়ার্ডটি ভিউ থেকে পাওয়ার জন্য হ্যান্ডলারটিকে অনুরোধ করে ...

bool loginResult = Login(Username, PasswordHandler());

এইভাবে, যখন আমি ভিউমডেলটি পরীক্ষা করতে চাই তখন আমি কেবল পাসওয়ার্ডহ্যান্ডলারকে একটি বেনামি পদ্ধতিতে সেট করতে পারি যা পরীক্ষায় আমি যে পাসওয়ার্ডটি ব্যবহার করতে চাই তা বিতরণ করতে দেয়।


4

আমি অনুভব করেছি যে আমি আমার সমাধানটি মিশ্রণে ফেলে দেব, যেহেতু এটি একটি সাধারণ সমস্যা ... এবং প্রচুর বিকল্প থাকা সর্বদা একটি ভাল জিনিস।

আমি কেবল একটি আবৃত PasswordBoxএকটি UserControlএবং একটি বাস্তবায়িত DependencyPropertyজুড়তে অনুমতি পাবে। মেমরিতে কোনও স্পষ্ট পাঠ্য সংরক্ষণ না করার জন্য আমি যা যা করতে পারি তার সবই করছি, তাই সবকিছুই SecureStringএবং PasswordBox.Passwordসম্পত্তি দ্বারা সম্পন্ন হয় । foreachলুপ চলাকালীন , প্রতিটি চরিত্র প্রকাশিত হয় তবে এটি খুব সংক্ষেপে। সত্যিই, যদি আপনি এই সংক্ষিপ্ত এক্সপোজার থেকে আপনার ডাব্লুপিএফ অ্যাপ্লিকেশনটির সাথে আপোস করার বিষয়ে উদ্বিগ্ন হন তবে আপনার কাছে সুরক্ষার জন্য আরও বড় সমস্যা রয়েছে।

এর সৌন্দর্য হ'ল আপনি কোনও এমভিভিএম বিধি, এমনকি "পিউরিস্ট" বিধিগুলি ভঙ্গ করছেন না, যেহেতু এটি একটি UserControl, তাই এটি কোড-ব্যাকড রাখার অনুমতি দেয়। আপনি যখন এটি ব্যবহার করছেন তখন আপনার কোনও অংশ বা পাসওয়ার্ডের উত্স সম্পর্কে অবগত না হয়ে Viewএবং এর ViewModelমধ্যেও আপনার শুদ্ধ যোগাযোগ VideModelথাকতে Viewপারে। শুধু কি নিশ্চিত যে আপনি বাঁধাই করছেন তা SecureStringআপনার ViewModel

BindablePasswordBox.xaml

<UserControl x:Class="BK.WPF.CustomControls.BindanblePasswordBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" d:DesignHeight="22" d:DesignWidth="150">
    <PasswordBox x:Name="PswdBox"/>
</UserControl>

বাইন্ডেবলপ্যাসওয়ার্ডবক্স.এক্স্যামল সিএস (সংস্করণ 1 - কোনও দ্বি-মুখী বাঁধাই সমর্থন নয়))

using System.ComponentModel;
using System.Security;
using System.Windows;
using System.Windows.Controls;

namespace BK.WPF.CustomControls
{
    public partial class BindanblePasswordBox : UserControl
    {
        public static readonly DependencyProperty PasswordProperty =
            DependencyProperty.Register("Password", typeof(SecureString), typeof(BindanblePasswordBox));

        public SecureString Password
        {
            get { return (SecureString)GetValue(PasswordProperty); }
            set { SetValue(PasswordProperty, value); }
        }

        public BindanblePasswordBox()
        {
            InitializeComponent();
            PswdBox.PasswordChanged += PswdBox_PasswordChanged;
        }

        private void PswdBox_PasswordChanged(object sender, RoutedEventArgs e)
        {
            var secure = new SecureString();
            foreach (var c in PswdBox.Password)
            {
                secure.AppendChar(c);
            }
            Password = secure;
        }
    }
}

সংস্করণ 1 এর ব্যবহার:

<local:BindanblePasswordBox Width="150" HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                            Password="{Binding Password, Mode=OneWayToSource}"/>

বাইন্ডেবলপ্যাসওয়ার্ডবক্স.এক্স্যামল সিএস (সংস্করণ 2 - দ্বি-মুখী বাইন্ডিং সমর্থন রয়েছে))

public partial class BindablePasswordBox : UserControl
{
    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(SecureString), typeof(BindablePasswordBox),
        new PropertyMetadata(PasswordChanged));

    public SecureString Password
    {
        get { return (SecureString)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    public BindablePasswordBox()
    {
        InitializeComponent();
        PswdBox.PasswordChanged += PswdBox_PasswordChanged;
    }

    private void PswdBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        var secure = new SecureString();
        foreach (var c in PswdBox.Password)
        {
            secure.AppendChar(c);
        }
        if (Password != secure)
        {
            Password = secure;
        }
    }

    private static void PasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var pswdBox = d as BindablePasswordBox;
        if (pswdBox != null && e.NewValue != e.OldValue)
        {
            var newValue = e.NewValue as SecureString;
            if (newValue == null)
            {
                return;
            }

            var unmanagedString = IntPtr.Zero;
            string newString;
            try
            {
                unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(newValue);
                newString = Marshal.PtrToStringUni(unmanagedString);
            }
            finally
            {
                Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
            }

            var currentValue = pswdBox.PswdBox.Password;
            if (currentValue != newString)
            {
                pswdBox.PswdBox.Password = newString;
            }
        }
    }
}

সংস্করণ 2 এর ব্যবহার:

<local:BindanblePasswordBox Width="150" HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                            Password="{Binding Password, Mode=TwoWay}"/>

আমি এটি বাস্তবায়নের চেষ্টা করেছি, আপনি যখন ইউআই-তে পাসওয়ার্ড আপডেট করবেন তখন আপনি একটি অসীম লুপ পাবেন; কারণ if (Password != secure)সিকিউরস্ট্রিং সমান ওভাররাইড না করায় সর্বদা মিথ্যা হবে। কোন চিন্তা?
সিমোনালেক্সান্ডার 20055


2

আমি এই পদ্ধতিটি ব্যবহার করেছি এবং পাসওয়ার্ড বাক্সটি পাস করেছি, যদিও এটি এমভিভিএম লঙ্ঘন করে না কেন এটি আমার পক্ষে অপরিহার্য ছিল কারণ আমি আমার শেলের মধ্যে লগইন করার জন্য ডেটা টেমপ্লেট সহ একটি সামগ্রী নিয়ন্ত্রণ ব্যবহার করে যা একটি জটিল শেল এনভায়রওমেন্ট। সুতরাং শেলের পিছনের কোডটি অ্যাক্সেস করা বাজে হত।

পাসওয়ার্ডবক্সটি পাস করা আমার মনে হবে যতদূর আমি জানি কোড থেকে নিয়ন্ত্রণ অ্যাক্সেস করার সমান। আমি পাসওয়ার্ডগুলি সম্মত করি, স্মৃতিতে রাখি না ইত্যাদি এই বাস্তবায়নে আমার ভিউ মডেলে পাসওয়ার্ডের সম্পত্তি নেই।

বাটন কমান্ড

Command="{Binding Path=DataContext.LoginCommand, ElementName=MyShell}" CommandParameter="{Binding ElementName=PasswordBox}"

ViewModel

private void Login(object parameter)
{
    System.Windows.Controls.PasswordBox p = (System.Windows.Controls.PasswordBox)parameter;
    MessageBox.Show(p.Password);
}

এটি এমভিভিএম প্যাটার্নের স্পষ্ট লঙ্ঘন। প্যাটার্নটি ভিউ মডেলে নিয়ন্ত্রণগুলি পরিচালনা করতে দেয় না।
বায়োনিক কোড

2

আমার কাছে এই দুটি জিনিসই ভুল অনুভব করছে:

  • পরিষ্কার পাঠ্য পাসওয়ার্ডের বৈশিষ্ট্য কার্যকর করা হচ্ছে
  • PasswordBoxভিউমোডেলে কমান্ড প্যারামিটার হিসাবে প্রেরণ করা হচ্ছে

স্টিভ সিও-তে বর্ণিত সিকিউরপ্যাসওয়ার্ড (সিকিউরস্ট্রিং উদাহরণ) স্থানান্তরিত করা গ্রহণযোগ্য বলে মনে হয়। আমি Behaviorsপিছনে কোড করতে পছন্দ করি এবং আমার ভিউ মডেল থেকে পাসওয়ার্ডটি পুনরায় সেট করতে সক্ষম হওয়ার অতিরিক্ত প্রয়োজনীয়তাও ছিল।

Xaml ( Passwordভিউমোডেল সম্পত্তি):

<PasswordBox>
    <i:Interaction.Behaviors>
        <behaviors:PasswordBinding BoundPassword="{Binding Password, Mode=TwoWay}" />
    </i:Interaction.Behaviors>
</PasswordBox>

আচরণ:

using System.Security;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace Evidence.OutlookIntegration.AddinLogic.Behaviors
{
    /// <summary>
    /// Intermediate class that handles password box binding (which is not possible directly).
    /// </summary>
    public class PasswordBoxBindingBehavior : Behavior<PasswordBox>
    {
        // BoundPassword
        public SecureString BoundPassword { get { return (SecureString)GetValue(BoundPasswordProperty); } set { SetValue(BoundPasswordProperty, value); } }
        public static readonly DependencyProperty BoundPasswordProperty = DependencyProperty.Register("BoundPassword", typeof(SecureString), typeof(PasswordBoxBindingBehavior), new FrameworkPropertyMetadata(OnBoundPasswordChanged));

        protected override void OnAttached()
        {
            this.AssociatedObject.PasswordChanged += AssociatedObjectOnPasswordChanged;
            base.OnAttached();
        }

        /// <summary>
        /// Link up the intermediate SecureString (BoundPassword) to the UI instance
        /// </summary>
        private void AssociatedObjectOnPasswordChanged(object s, RoutedEventArgs e)
        {
            this.BoundPassword = this.AssociatedObject.SecurePassword;
        }

        /// <summary>
        /// Reacts to password reset on viewmodel (ViewModel.Password = new SecureString())
        /// </summary>
        private static void OnBoundPasswordChanged(object s, DependencyPropertyChangedEventArgs e)
        {
            var box = ((PasswordBoxBindingBehavior)s).AssociatedObject;
            if (box != null)
            {
                if (((SecureString)e.NewValue).Length == 0)
                    box.Password = string.Empty;
            }
        }

    }
}

2

আমার মত সম্পূর্ণ newbies জন্য, Konamimanউপরে পরামর্শ দেওয়া একটি সম্পূর্ণ কাজের নমুনা এখানে । ধন্যবাদ Konamiman

XAML

    <PasswordBox x:Name="textBoxPassword"/>
    <Button x:Name="buttonLogin" Content="Login"
            Command="{Binding PasswordCommand}"
            CommandParameter="{Binding ElementName=textBoxPassword}"/> 

ViewModel

public class YourViewModel : ViewModelBase
{
    private ICommand _passwordCommand;
    public ICommand PasswordCommand
    {
        get {
            if (_passwordCommand == null) {
                _passwordCommand = new RelayCommand<object>(PasswordClick);
            }
            return _passwordCommand;
        }
    }

    public YourViewModel()
    {
    }

    private void PasswordClick(object p)
    {
        var password = p as PasswordBox;
        Console.WriteLine("Password is: {0}", password.Password);
    }
}

এটি এমভিভিএম প্যাটার্নের স্পষ্ট লঙ্ঘন। প্যাটার্নটি ভিউ মডেলে নিয়ন্ত্রণগুলি পরিচালনা করতে দেয় না।
বায়োনিক কোড

1

আপনি দেখতে পাচ্ছেন যে আমি পাসওয়ার্ডের সাথে আবদ্ধ, তবে এটি এটি স্থির শ্রেণীর সাথে আবদ্ধ ..

এটি একটি সংযুক্ত সম্পত্তি । এই ধরণের সম্পত্তি কোনও ধরণের ক্ষেত্রেই প্রয়োগ করা যেতে পারে DependencyObject, কেবল যে ধরণের ক্ষেত্রে এটি ঘোষণা করা হয় তা নয়। এটি PasswordHelperস্থির শ্রেণিতে ঘোষণা করা সত্ত্বেও , PasswordBoxআপনি এটি ব্যবহার করেন তার উপর এটি প্রয়োগ করা হয় ।

এই সংযুক্ত সম্পত্তিটি ব্যবহার করতে, আপনার এটিকে Passwordআপনার ভিউমোডেলের সম্পত্তিটিতে আবদ্ধ করতে হবে :

<PasswordBox w:PasswordHelper.Attach="True" 
         w:PasswordHelper.Password="{Binding Password}"/>

1

আমি এরকম কাজ করেছি:

XAML:

<PasswordBox x:Name="NewPassword" PasswordChanged="NewPassword_PasswordChanged"/>
<!--change tablenameViewSource: yours!-->
<Grid DataContext="{StaticResource tablenameViewSource}" Visibility="Hidden">
        <TextBox x:Name="Password" Text="{Binding password, Mode=TwoWay}"/>
</Grid>

সি #:

private void NewPassword_PasswordChanged(object sender, RoutedEventArgs e)
    {
        try
        {
           //change tablenameDataTable: yours! and tablenameViewSource: yours!
           tablenameDataTable.Rows[tablenameViewSource.View.CurrentPosition]["password"] = NewPassword.Password;
        }
        catch
        {
            this.Password.Text = this.NewPassword.Password;
        }
    }

এটা আমার জন্য কাজ করে!


আপনি আমাকে একটি সুন্দর ধারণা দিন। :)
আন্দ্রে মেন্ডোনকা

1

যেমনটি আগে উল্লেখ করা হয়েছে ভিএম ভিউ সম্পর্কে অসচেতন হওয়া উচিত তবে পুরো পাসওয়ার্ডবক্সটি পাস করা সহজ পদ্ধতির মতো দেখায়। সুতরাং পাসওয়ার্ডবক্সে পাস করা প্যারামিটার কাস্টিংয়ের পরিবর্তে এটি থেকে পাসওয়ার্ডের সম্পত্তি বের করতে রিফ্লেকশন ব্যবহার করুন। এক্ষেত্রে ভিএম সম্পত্তি পাসওয়ার্ড সহ এক ধরণের পাসওয়ার্ড ধারককে প্রত্যাশা করে (আমি এমভিএমএম লাইট-টুলকিট থেকে রিলে কম্যান্ড ব্যবহার করছি):

public RelayCommand<object> SignIn
{
    get
    {
        if (this.signIn == null)
        {
            this.signIn = new RelayCommand<object>((passwordContainer) => 
                {
                    var password = passwordContainer.GetType().GetProperty("Password").GetValue(passwordContainer) as string;
                    this.authenticationService.Authenticate(this.Login, password);
                });
        }

        return this.signIn;
    }
}

এটি বেনাম শ্রেণীর সাথে সহজেই পরীক্ষা করা যেতে পারে:

var passwordContainer = new
    {
        Password = "password"
    };

মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
স্যামুয়েল লিউ

1

উইন্ডোজ সর্বজনীন অ্যাপে

আপনি এই কোডটি "পাসওয়ার্ড" বৈশিষ্ট্যযুক্ত এবং মডেল ভিউয়ের সাথে আবদ্ধ করতে ব্যবহার করতে পারেন

 <PasswordBox x:Uid="PasswordBox" Password="{Binding Waiter.Password, Mode=TwoWay}" Name="txtPassword" HorizontalAlignment="Stretch" Margin="50,200,50,0" VerticalAlignment="Top"/>


1

এই বাস্তবায়নটি যে ঝুঁকিগুলি সম্পর্কে অবগত রয়েছে তার জন্য, আপনার ভিউমোডেলটিতে পাসওয়ার্ড সিঙ্ক করার জন্য কেবল মোড = ওয়ানওয়েটোসোর্স যুক্ত করুন

XAML

<PasswordBox
    ff:PasswordHelper.Attach="True"
    ff:PasswordHelper.Password="{Binding Path=Password, Mode=OneWayToSource}" />

কেন শুধু না OneWayToSource?
বিকে

@ বি কে আমার উত্তর সম্পাদনা করেছেন ধন্যবাদ।
কেভিন

1
বাঁধনকারী ধনুর্বন্ধনী ভিতরে মোড থাকা উচিত নয়?
মাদুর

@ ম্যাট ইয়াপ ধন্যবাদ।
কেভিন

1

এটি আমার গ্রহণ করা এখানে:

  1. পাসওয়ার্ডকে সংযুক্ত করতে একটি সংযুক্ত সম্পত্তি ব্যবহার করা পাসওয়ার্ড সুরক্ষার উদ্দেশ্যকে পরাস্ত করে। একটি পাসওয়ার্ড বাক্সের পাসওয়ার্ড সম্পত্তি কোনও কারণে বাইন্ডেবল নয়।

  2. কমান্ড প্যারামিটার হিসাবে পাসওয়ার্ড বাক্সটি পাস করা ভিউমোডেলটিকে নিয়ন্ত্রণ সম্পর্কে সচেতন করবে। আপনি যদি নিজের ভিউমোডেলটিকে পুনরায় ব্যবহারযোগ্য ক্রস প্ল্যাটফর্ম বানানোর পরিকল্পনা করেন তবে এটি কাজ করবে না। আপনার ভিএমকে আপনার ভিউ বা অন্য কোনও নিয়ন্ত্রণ সম্পর্কে সচেতন করবেন না।

  3. আমি মনে করি না যে কোনও নতুন সম্পত্তি, একটি ইন্টারফেস, পাসওয়ার্ড পরিবর্তিত ইভেন্টগুলিতে সাবস্ক্রাইব করা বা অন্য কোনও জটিল বিষয় পাসওয়ার্ড দেওয়ার সহজ কাজের জন্য প্রয়োজনীয়।

XAML

<PasswordBox x:Name="pbPassword" />
<Button Content="Login" Command="{Binding LoginCommand}" x:Name="btnLogin"/>

কোড পিছনে - পিছনে কোড ব্যবহার করা অগত্যা এমভিভিএম লঙ্ঘন করে না। যতক্ষণ না আপনি এতে কোনও ব্যবসায়িক যুক্তি রাখবেন না।

btnLogin.CommandParameter = new Func<string>(()=>pbPassword.Password); 

ViewModel

LoginCommand = new RelayCommand<Func<string>>(getpwd=> { service.Login(username, getpwd()); });

0

আপনি ডাব্লুপিএফ অ্যাপ্লিকেশন ফ্রেমওয়ার্ক (ডাব্লুএফ) প্রকল্পের ভিউমোডেল নমুনা অ্যাপ্লিকেশনটিতে পাসওয়ার্ডবক্সের জন্য একটি সমাধান খুঁজে পান ।

তবে জাস্টিন ঠিক বলেছেন ভিউ এবং ভিউমডেলের মধ্যে সরল পাঠ্য হিসাবে পাসওয়ার্ডটি পাস করবেন না। পরিবর্তে সিকিউরস্ট্রিং ব্যবহার করুন (এমএসডিএন পাসওয়ার্ডবক্স দেখুন)।


2
ডাব্লুএএফ এর পপ 3সেটিংভিউতে যেভাবে ব্যবহৃত হয় তা মজার। পাসওয়ার্ডবক্স পাসওয়ার্ডবক্স = (পাসওয়ার্ডবক্স) প্রেরক; if (ভিউমোডেল! = নাল) {ভিউমোডেল.পপ 3 পাসওয়ার্ড = পাসওয়ার্ডবক্স.প্যাসওয়ার্ড; View ভিউমোডেলের পপ 3 পাসওয়ার্ড হ'ল স্ট্রিং বৈশিষ্ট্য। সুতরাং, এটির পাশাপাশি সুরক্ষিত নয় ... সংযুক্ত সম্পত্তিটি ব্যবহার করা আরও ভাল
মাইকেল সিঙ্ক

0

ডেটা ক্লাসে পাসওয়ার্ড লেখার জন্য আমি একটি প্রমাণীকরণ যাচাই করেছিলাম যার পরে একটি মধ্যস্থতাকারী শ্রেণি কর্তৃক ডাকে উপ দ্বারা ডাকে an

এটি একটি নিখুঁত সমাধান নয়; তবে এটি আমার পাসওয়ার্ডটি সরাতে না পারার সমস্যার সমাধান করে।


0

আমি সাসিঙ্ক্ট এমভিভিএম-বান্ধব সমাধান ব্যবহার করছি যা এখনও উল্লেখ করা হয়নি। প্রথম, আমি এক্সএএমএল-তে পাসওয়ার্ডবক্সের নাম রেখেছি:

<PasswordBox x:Name="Password" />

তারপরে আমি ভিউ কনস্ট্রাক্টরে একটি একক পদ্ধতি কল যুক্ত করব:

public LoginWindow()
{
    InitializeComponent();
    ExposeControl<LoginViewModel>.Expose(this, view => view.Password,
        (model, box) => model.SetPasswordBox(box));
}

এবং এটাই. ডেটা কনটেক্সট এর মাধ্যমে কোনও ভিউয়ের সাথে সংযুক্ত করা হলে এবং মডেলটি বিচ্ছিন্ন হয়ে যাওয়ার পরে বিজ্ঞপ্তিটি গ্রহণ করবে will এই বিজ্ঞপ্তির বিষয়বস্তুগুলি ল্যাম্বডাসের মাধ্যমে কনফিগারযোগ্য, তবে সাধারণত এটি পরামিতি হিসাবে সমস্যাযুক্ত নিয়ন্ত্রণকে পাস করে ভিউ মডেলে কেবল একটি সেটার বা পদ্ধতি কল হয়।

চাইল্ড কন্ট্রোলের পরিবর্তে ভিউ এক্সপোজ ইন্টারফেসের মাধ্যমে এটি খুব সহজেই এমভিভিএম বান্ধব করা যায়।

উপরের কোডটি আমার ব্লগে প্রকাশিত সহায়ক শ্রেণীর উপর নির্ভর করে ।


0

আমি এই কাজটি করার চেষ্টা করে যুগে যুগে কাটিয়েছি। শেষ পর্যন্ত, আমি ছেড়ে দিয়েছিলাম এবং কেবল ডেভএক্সপ্রেস থেকে পাসওয়ার্ডবক্সএডিট ব্যবহার করেছি।

এটি সর্বকালের সবচেয়ে সহজ সমাধান, কারণ এটি কোনও ভয়ঙ্কর কৌশল না টানাই বাঁধাইয়ের অনুমতি দেয়।

ডিভ এক্সপ্রেস ওয়েবসাইটে সমাধান

রেকর্ডের জন্য, আমি কোনওভাবেই ডিএক্সপ্রেসের সাথে অনুমোদিত নই।


0

<UserControl x:Class="Elections.Server.Handler.Views.LoginView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
             xmlns:cal="http://www.caliburnproject.org"
             mc:Ignorable="d" 
             Height="531" Width="1096">
    <ContentControl>
        <ContentControl.Background>
            <ImageBrush/>
        </ContentControl.Background>
        <Grid >
            <Border BorderBrush="#FFABADB3" BorderThickness="1" HorizontalAlignment="Left" Height="23" Margin="900,100,0,0" VerticalAlignment="Top" Width="160">
                <TextBox TextWrapping="Wrap"/>
            </Border>
            <Border BorderBrush="#FFABADB3" BorderThickness="1" HorizontalAlignment="Left" Height="23" Margin="900,150,0,0" VerticalAlignment="Top" Width="160">
                <PasswordBox x:Name="PasswordBox"/>
            </Border>
            <Button Content="Login" HorizontalAlignment="Left" Margin="985,200,0,0" VerticalAlignment="Top" Width="75">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <cal:ActionMessage MethodName="Login">
                            <cal:Parameter Value="{Binding ElementName=PasswordBox}" />
                        </cal:ActionMessage>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>

        </Grid>
    </ContentControl>
</UserControl>

using System;
using System.Windows;
using System.Windows.Controls;
using Caliburn.Micro;

namespace Elections.Server.Handler.ViewModels
{
    public class LoginViewModel : PropertyChangedBase
    {
        MainViewModel _mainViewModel;
        public void SetMain(MainViewModel mainViewModel)
        {
            _mainViewModel = mainViewModel;
        }

        public void Login(Object password)
        {
            var pass = (PasswordBox) password;
            MessageBox.Show(pass.Password);

            //_mainViewModel.ScreenView = _mainViewModel.ControlPanelView;
            //_mainViewModel.TitleWindow = "Panel de Control";
            //HandlerBootstrapper.Title(_mainViewModel.TitleWindow);
        }
    }
}

;) সহজ!


0

এটা খুবই সাধারণ . পাসওয়ার্ডের জন্য অন্য একটি সম্পত্তি তৈরি করুন এবং এটি টেক্সটবক্সের সাথে আবদ্ধ করুন

তবে সমস্ত ইনপুট ক্রিয়াকলাপ প্রকৃত পাসওয়ার্ডের সম্পত্তি সহ সম্পাদন করে

ব্যক্তিগত স্ট্রিং_প্যাসওয়ার্ড;

    public string PasswordChar
    {
        get
        {
            string szChar = "";

            foreach(char szCahr in _Password)
            {
                szChar = szChar + "*";
            }

            return szChar;
        }

        set
        {
            _PasswordChar = value; NotifyPropertyChanged();
        }
    }

পাবলিক স্ট্রিং পাসওয়ার্ড {get {ফেরত _ পাসওয়ার্ড; }

        set
        {
            _Password = value; NotifyPropertyChanged();
            PasswordChar = _Password;
        }
    }


পাসওয়ার্ড বাক্স বাইন্ডেবল না হওয়ার কারণ হ'ল আমরা পরিষ্কার স্ট্রিংয়ে পাসওয়ার্ড সংরক্ষণ করতে চাই না। স্ট্রিং অপরিবর্তনীয় এবং আমরা নিশ্চিত নই যে এটি কতক্ষণ স্মৃতিতে থাকবে।
ল্যান্স

0

আমার উত্তরটি এমভিভিএম প্যাটার্নের জন্য আরও সহজ

ক্লাস ভিউমডেল

public string password;

PasswordChangedCommand = new DelegateCommand<RoutedEventArgs>(PasswordChanged);

Private void PasswordChanged(RoutedEventArgs obj)

{

    var e = (WatermarkPasswordBox)obj.OriginalSource;

    //or depending or what are you using

    var e = (PasswordBox)obj.OriginalSource;

    password =e.Password;

}

পাসওয়ার্ডবক্সের পাসওয়ার্ড বৈশিষ্ট্য যা জিতেছে বা এক্সসিডটোকলকিট সরবরাহ করে এমন ওয়াটারমার্কপ্যাসওয়ার্ডবক্স একটি রাউটেডভেন্টআর্গগুলি উত্পন্ন করে যাতে আপনি এটিকে আবদ্ধ করতে পারেন।

এখন xmal দৃষ্টিতে

<Xceed:WatermarkPasswordBox Watermark="Input your Password" Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="7" PasswordChar="*" >

        <i:Interaction.Triggers>

            <i:EventTrigger EventName="PasswordChanged">

                <prism:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path= DataContext.PasswordChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path= Password}"/>

            </i:EventTrigger>

        </i:Interaction.Triggers>

    </Xceed:WatermarkPasswordBox>

অথবা

<PasswordBox Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="7" PasswordChar="*" >

        <i:Interaction.Triggers>

            <i:EventTrigger EventName="PasswordChanged">

                <prism:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path= DataContext.PasswordChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path= Password}"/>

            </i:EventTrigger>

        </i:Interaction.Triggers>

    </PasswordBox>

0

SecureStringসংযুক্ত আচরণ এবং ব্যবহার করে দর্শন মডেলটিতে একটি প্রেরণ করুনICommand

এমভিভিএম প্রয়োগ করার সময় কোড-পিছনে কোনও সমস্যা নেই। এমভিভিএম একটি স্থাপত্য নিদর্শন যা লক্ষ্যটি মডেল / ব্যবসায়িক যুক্তি থেকে পৃথক করে। এমভিভিএম বর্ণনা করে যে কীভাবে পুনরুত্পাদনযোগ্য উপায়ে (প্যাটার্ন) এই লক্ষ্য অর্জন করা যায়। আপনি কীভাবে দৃষ্টিভঙ্গিটি গঠন করেন বা বাস্তবায়ন করেন তার মতো প্রয়োগের বিশদ সম্পর্কে এটি যত্নশীল নয়। এটি কেবল সীমানা অঙ্কন করে এবং এই প্যাটার্নের পরিভাষার ক্ষেত্রে দৃষ্টিভঙ্গি, দর্শন মডেল এবং মডেল কী তা নির্ধারণ করে।

এমভিভিএম ভাষা (এক্সএএমএল বা সি #) বা সংকলক সম্পর্কে চিন্তা করে না (partial ক্লাস) । ভাষা স্বাধীন হওয়া কোনও ডিজাইনের ধরণের বাধ্যতামূলক বৈশিষ্ট্য - এটি অবশ্যই ভাষা নিরপেক্ষ হতে হবে।

যাইহোক, কোড-পিছনে XIL এবং C # এর মধ্যে বন্যভাবে বিতরণ করা হলে আপনার ইউআই লজিককে বোঝা আরও শক্ত করে তোলার মতো কিছু ড্র ব্যাক রয়েছে। তবে সর্বাধিক গুরুত্বপূর্ণ বাস্তবায়ন UI যুক্তি বা টেমপ্লেট, শৈলী, ট্রিগার, অ্যানিমেশন ইত্যাদির মতো সি # তে এক্সএএমএল ব্যবহারের চেয়ে খুব জটিল এবং কুরুচিপূর্ণ / কম পঠনযোগ্য। এক্সএএমএল হ'ল একটি মার্কআপ ল্যাঙ্গুয়েজ যা বস্তুর শ্রেণিবিন্যাসের ভিজ্যুয়ালাইজ করতে ট্যাগ এবং নেস্টিং ব্যবহার করে। এক্সএএমএল ব্যবহার করে ইউআই তৈরি করা খুব সুবিধাজনক। যদিও এমন পরিস্থিতি রয়েছে যেখানে আপনি সি # (বা কোড-পিছনে) ইউআই যুক্তি প্রয়োগ করতে পছন্দ করছেন। হ্যান্ডলিংPasswordBox করা একটি উদাহরণ।

এই কারণে PasswordBoxকোডটি হ্যান্ডেল করে পিছনে হ্যান্ডেল করা PasswordBox.PasswordChangedএমভিভিএম প্যাটার্নের লঙ্ঘন নয়।

একটি স্পষ্ট লঙ্ঘন হ'ল PasswordBoxভিউ মডেলটিতে একটি নিয়ন্ত্রণ (দ্য ) দেওয়া। অনেক সমাধান সুপারিশ করেছে যেমন, উপসাগর উদাহরণস্বরূপ ক্ষণস্থায়ী PasswordBoxযেমনICommand.CommandParameter দেয়, ভিউ মডেল । অবশ্যই খুব খারাপ এবং অপ্রয়োজনীয় সুপারিশ recommend

আপনি যদি সি # ব্যবহারের বিষয়ে চিন্তা না করেন তবে কেবল আপনার কোড-পেছনের ফাইলটি পরিষ্কার রাখতে চান বা কেবল কোনও আচরণ / ইউআই যুক্তি সজ্জিত করতে চান, আপনি সর্বদা সংযুক্ত বৈশিষ্ট্য ব্যবহার করতে পারেন এবং একটি সংযুক্ত আচরণ প্রয়োগ করতে পারেন।

প্লেইন টেক্সট পাসওয়ার্ড (সত্যই খারাপ অ্যান্টি-প্যাটার্ন এবং সুরক্ষা ঝুঁকি) আবদ্ধ করতে সক্ষম করে এমন কুখ্যাত প্রশস্ত স্প্রেড সহায়কটির বিরোধিতা করে, এই আচরণটি যখনই ইভেন্টটি উত্থাপন করে তখন ভিউ মডেল ICommandহিসাবে পাসওয়ার্ড প্রেরণ করতে ব্যবহার করে ।SecureStringPasswordBoxPasswordBox.PasswordChanged

MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <PasswordBox PasswordBox.Command="{Binding VerifyPasswordCommand}" />
</Window>

ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{
  public ICommand VerifyPasswordCommand => new RelayCommand(VerifyPassword);

  public void VerifyPassword(object commadParameter)
  {
    if (commandParameter is SecureString secureString)
    {
      IntPtr valuePtr = IntPtr.Zero;
      try
      {
        valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
        string plainTextPassword = Marshal.PtrToStringUni(valuePtr);

        // Handle plain text password. 
        // It's recommended to convert the SecureString to plain text in the model, when really needed.
      } 
      finally 
      {
        Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
      }
    }
  }
}

PasswordBox.cs

// Attached behavior
class PasswordBox : DependencyObject
{
  #region Command attached property

  public static readonly DependencyProperty CommandProperty =
    DependencyProperty.RegisterAttached(
      "Command",
      typeof(ICommand),
      typeof(PasswordBox),
      new PropertyMetadata(default(ICommand), PasswordBox.OnSendPasswordCommandChanged));

  public static void SetCommand(DependencyObject attachingElement, ICommand value) =>
    attachingElement.SetValue(PasswordBox.CommandProperty, value);

  public static ICommand GetCommand(DependencyObject attachingElement) =>
    (ICommand) attachingElement.GetValue(PasswordBox.CommandProperty);

  #endregion

  private static void OnSendPasswordCommandChanged(
    DependencyObject attachingElement,
    DependencyPropertyChangedEventArgs e)
  {
    if (!(attachingElement is System.Windows.Controls.PasswordBox passwordBox))
    {
      throw new ArgumentException("Attaching element must be of type 'PasswordBox'");
    }

    if (e.OldValue != null)
    {
      return;
    }

    WeakEventManager<object, RoutedEventArgs>.AddHandler(
      passwordBox,
      nameof(System.Windows.Controls.PasswordBox.PasswordChanged),
      SendPassword_OnPasswordChanged);
  }

  private static void SendPassword_OnPasswordChanged(object sender, RoutedEventArgs e)
  {
    var attachedElement = sender as System.Windows.Controls.PasswordBox;
    SecureString commandParameter = attachedElement?.SecurePassword;
    if (commandParameter == null || commandParameter.Length < 1)
    {
      return;
    }

    ICommand sendCommand = GetCommand(attachedElement);
    sendCommand?.Execute(commandParameter);
  }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.