Windows Credential Management with the .net

系统 1951 0
原文链接
<meta name="ProgId" content="Word.Document"> <meta name="Generator" content="Microsoft Word 11"> <meta name="Originator" content="Microsoft Word 11"> <link rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C03%5Cclip_filelist.xml"> <link rel="Edit-Time-Data" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C03%5Cclip_editdata.mso"> <!--[if !mso]> <style> v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} </style> <![endif]--><!--[if gte mso 9]><xml> <w:worddocument> <w:view>Normal</w:view> <w:zoom>0</w:zoom> <w:punctuationkerning/> <w:drawinggridverticalspacing>7.8 磅</w:drawinggridverticalspacing> <w:displayhorizontaldrawinggridevery>0</w:displayhorizontaldrawinggridevery> <w:displayverticaldrawinggridevery>2</w:displayverticaldrawinggridevery> <w:validateagainstschemas/> <w:saveifxmlinvalid>false</w:saveifxmlinvalid> <w:ignoremixedcontent>false</w:ignoremixedcontent> <w:alwaysshowplaceholdertext>false</w:alwaysshowplaceholdertext> <w:compatibility> <w:spaceforul/> <w:balancesinglebytedoublebytewidth/> <w:donotleavebackslashalone/> <w:ultrailspace/> <w:donotexpandshiftreturn/> <w:adjustlineheightintable/> <w:breakwrappedtables/> <w:snaptogridincell/> <w:wraptextwithpunct/> <w:useasianbreakrules/> <w:dontgrowautofit/> <w:usefelayout/> </w:compatibility> <w:browserlevel>MicrosoftInternetExplorer4</w:browserlevel> </w:worddocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:latentstyles deflockedstate="false" latentstylecount="156"> </w:latentstyles> </xml><![endif]--><style> <!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"\@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} h4 {mso-margin-top-alt:auto; margin-right:0cm; mso-margin-bottom-alt:auto; margin-left:0cm; mso-pagination:widow-orphan; mso-outline-level:4; font-size:12.0pt; font-family:宋体; mso-bidi-font-family:宋体;} a:link, span.MsoHyperlink {color:blue; text-decoration:underline; text-underline:single;} a:visited, span.MsoHyperlinkFollowed {color:purple; text-decoration:underline; text-underline:single;} pre {margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:宋体; mso-bidi-font-family:宋体;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} --> </style> <!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]-->

Windows Credential Management with the .net Framework 2.0

Kenny kerr

January 2006

Applies to:

Microsoft .NET Framework 2.0
NET Framework Security
Windows XP

概叙:这篇文章主要是介绍 Credential Management API 怎样处理界面和用户的凭证集合。同时也提供了一个能够做一些简单凭证管理的类库,可以被 c# vb.net 调用。

下载相关的例程: KerrCredentialsSample.exe

内容

介绍

请求凭证

托管代码的请求凭证

一个工具:请求凭证生成器

SecureString 基础

凭证集合

在托管代码中使用凭证集合

工具:凭证集合管理器

结论

 

 

介绍

管理用户凭证是一件非常困难的事情。理想上你的 windows 域凭证应该有足够的权限来访问你可能需要的资源。但是有这么简单吗?你可能不可避免的要去处理不同的安全权限,包括 windows 域, Microsoft Passport 和应用程序指定的验证策略。好像那些还不够挑战,凭证可能来自不同的 form ,包括 smart cards, certificates 和密码。

 

自从 2001 windows xp 发布, windows 包含了 credential management api 去管理用户凭证。这些 api 的设计是为了简化内部程序用户凭证管理,也为你自己的相关凭证管理提供了一致的安全的方法。她也可以被用来请求不需要被持久化的凭证,或者持久化你的应用程序的凭证,比如用数据保护 api Data Protection API .

 

在这篇文章我会介绍 windows credential management api 包括界面处理,凭证集合管理。介绍这些 api 的一个挑战是依赖你的背景知识和你怎么去用她,这些是一个 c-style api ,适用于 visual c++ 或者任何一款支持 windows 的编译器。因为流行 .net 框架的原因,一个理想的解决方案还应该包括 .net 框架的支持托管代码的集合。所以也提供了一个功 .net 框架调用的类库。

 

最后要说明的是: 当我解释 windows credential management 用到的不同的函数,结构,也包括列在表格中的相关的选项,标志和属性。虽然这些选项我的解释很多都是依赖与 sdk msndn 类库,但是我不止是简单的从文档中 copy 说明,我是尽力想你说明她的一些你可能不能完全掌握的细节。这些都是基于我写 credential management 经验的积累。

 

请求凭证

如果你所需要得是你得域凭证,那么你不需要请求凭证。因为在你登陆会话时已经被验证,你可以访问你可能能访问的所有资源。明显的这是一个不现实的例子。所以你需要请求用户的凭证。在过去,不用的应用程序创建不用的用户界面来请求用户的凭证,但是在 windows xp 上,应用程序可以依靠内建的,简单的,安全的用户界面给用户输入。

Windows 提供了 CredUIPromptForCredentials 函数显示一个可以配置的窗体去接收用户的凭证信息。

    
      DWORD WINAPI CredUIPromptForCredentialsW(PCREDUI_INFOW info,
    
  
    
      
                                                 
      
      PCWSTR targetName,
    
  
    
      
                                                 
      
      PCtxtHandle reserved,
    
  
    
      
                                                 
      
      DWORD errorCode,
    
  
    
      
                                                 
      
      PWSTR userName,
    
  
    
      
                          
      
      
                               
      
      ULONG userNameBufferSize,
    
  
    
      
                                                 
      
      PWSTR password,
    
  
    
      
                                                   
      
      ULONG passwordBufferSize,
    
  
    
      
                                                 
      
      PBOOL saveChecked,
    
  
    
      
      
      DWORD flags);
    
  
    因为这篇文章不是关于用
    
      c
    
    或者非托管的
    
      c++
    
    来管理用户凭证,所以我不对这个函数做过多细节的描叙。
  
    
      

 

    第一个参数只向一个
    
      CREDUI_INFO
    
    结构的指针,它允许你指定它的父窗体和默认的图标,标题,信息。
  
    
      

 

    
      
        targetName
      
    
    参数用来读取和写入凭证时的唯一定义,也被用来作为标题和信息的一部分,如果
    
      CREDUI_INFO
    
    没有被重写的话,晚些在我们讨论
    
      persisting
    
    凭证的时候你会对她认识的更深刻。
  
    
      Errorcode 
    
    参数允许窗体提供相应的错误代码,但是
    
      sdk
    
    没有提供相应的链接,所以这个参数几乎没什么用。
  
    
      username 
    
       userNameBufferSize
    
    参数用来指定初始化时的用户名。相应的
    
      password
    
      passwordBufferSize
    
    用来指定初始化的用户密码。这些使得用
    
      c
    
    和非托管的
    
      c++
    
    编程相当困难,你必须非常小心的处理这些字符串,像你在下一章看到的,托管代码可以非常简单的写出非常优秀的代码。
  
    
      

 

    这个窗体可以显示一个
    
      check box
    
    提供给用户来选择是否保存凭证。
    
      saveChecked 
    
    参数就是用来初始化这个
    
      check box 
    
    的状态用的。这个
    
      check box
    
    也可以在用户关闭窗体的时候来判断用户的喜好。注意的是这个参数被忽略,当凭证不是
    
      generic
    
    凭证的时候。
  

 

最好, falgs 参数允许你指定一个联合的标识。这里的问题是错误的混合不同的标识也会导致程序的错误。

 

相比探索这个函数的更多细节,我将会提供一些为简单任务的解决方案给你,用托管代码写的。在那之前,我们先来看一看一个用 C++ 写的例子。这个例子调用 CredUIPromptForCredentials

 

    
      CREDUI_INFO info = { sizeof (CREDUI_INFO) };
    
  
    
      info.hwndParent = GetSafeHwnd();
    
  
    
    
  
    
      info.pszCaptionText = L"Title";
    
  
    
      info.pszMessageText = L"Message";
    
  
    
    
  
    
      CBitmap bitmap;
    
  
    
      VERIFY(bitmap.LoadBitmap(IDB_PROMPT_BITMAP));
    
  
    
      info.hbmBanner = bitmap;
    
  
    
    
  
    
      CString target;
    
  
    
      const DWORD errorCode = 0;
    
  
    
    
  
    
      wchar_t userName[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
    
  
    
    
  
    
      wcscpy_s(userName,
    
  
    
      
                 
      
      _countof(userName),
    
  
    
      
                 
      
      L"initial user name");
    
  
    
    
  
    
      wchar_t password[CREDUI_MAX_PASSWORD_LENGTH + 1] = { 0 };
    
  
    
    
  
    
      BOOL saveChecked = false;
    
  
    
    
  
    
      Const DWORD flags = CREDUI_FLAGS_DO_NOT_PERSIST | 
    
  
    
      
                            
      
      CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX ;
    
  
    
    
  
    
      DWORD result = ::CredUIPromptForCredentials(&info,
    
  
    
      
                                                    
      
      target,
    
  
    
      
                                                    
      
      0, // reserved
    
  
    
      
                            
      
      
                                
      
      errorCode,
    
  
    
      
                                                    
      
      userName,
    
  
    
      
                                                    
      
      _countof(userName)
    
  
    
      
                                                    
      
      password,
    
  
    
      
                                                    
      
      _countof(password)
    
  
    
      
                                                    
      
      &saveChecked,
    
  
    
      
                                                    
      
      flags);
    
  
    
    
  
    
      switch (result)
    
  
    
      {
    
  
    
      
            
      
      case NO_ERROR:
    
  
    
      
            
      
      {
    
  
    
      
                
      
      // User chose OK...
    
  
    
      
                
      
      break;
    
  
    
      
            
      
      }
    
  
    
      
            
      
      case ERROR_CANCELLED:
    
  
    
      
            
      
      {
    
  
    
      
               
      
      
         
      
      // User chose Cancel...
    
  
    
      
                
      
      break;
    
  
    
      
            
      
      }
    
  
    
      
            
      
      default:
    
  
    
      
            
      
      {
    
  
    
      
                
      
      // Handle all other errors...
    
  
    
      
            
      
      }
    
  
    
      }
    
  
    
    
  
    
      ::SecureZeroMemory(password,
    
  
    
      
                           
      
      sizeof (password));
    
  

这段代码的结果是显示一下的窗体:

<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" style="'width:246pt; height:218.25pt'"> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\03\clip_image001.png" o:title=""/> </v:shape><![endif]--><!--[if !vml]--> Windows Credential Management with the .net Framework 2.0 <!--[endif]-->

正像你所看到的,有一大段代码是为了调用这个函数不会出错,首先,你要熟悉结构 CREDUI_INFO 去控制这个窗体的不同元素。接下来,你要为接收的用户名合密码准备缓冲区。和显示初始值。 CREDUI_MAX_USERNAME_LENGTH 常量表示用户名的最大长度。相同的 CREDUI_MAX_PASSWORD_LENGTH 表示密码的可能最大长度。在用户名和密码长度后面加 1 是为了加上介绍字符串 NULL, 调用 wcscpy_s 函数是为了显示用户名和密码的初始值。最后,我指定了两个标识,意思是,我不想 persist 这个凭证但是我想让保存密码的 check box 显示。 saveChecked 将会包括用户的选项。

显然在这里你很容易出错。

 

请求凭证,用托管代码

因为 CredUIPromptForCredentials

[C++]

    
      ref class MainWindow : Windows::Forms::Form
    
  
    
      {
    
  
    
      public:
    
  
    
      

 

    
      
            
      
      void Prompt()
    
  
    
      
            
      
      {
    
  
    
      
                
      
      PromptForCredentials dialog;
    
  
    
      

 

    
      
                
      
      dialog.Title = "Title";
    
  
    
      
                
      
      dialog.Message = "Message";
    
  
    
      
                
      
      dialog.Banner = Images::Banner;
    
  
    
      
                
      
      dialog.UserName = "initial user name";
    
  
    
      

 

    
      
                
      
      dialog.DoNotPersist = true;
    
  
    
      
                
      
      dialog.ShowSaveCheckBox = true;
    
  
    
      

 

    
      
                
      
      if (Windows::Forms::DialogResult::OK == dialog.ShowDialog(this))
    
  
    
      
                
      
      {
    
  
    
      
                    
      
      // Use credentials wisely...
    
  
    
      
                
      
      }
    
  
    
      
            
      
      }
    
  
    
      };
    
  

[C#]

    
      class MainWindow : Form
    
  
    
      {
    
  
    
      
            
      
      public void Prompt()
    
  
    
      
            
      
      {
    
  
    
      
                
      
      using (PromptForCredentials dialog = new PromptForCredentials())
    
  
    
      
                
      
      {
    
  
    
      
                    
      
      dialog.Title = "Title";
    
  
    
      
                    
      
      dialog.Message = "Message";
    
  
    
      
          
      
      
                  
      
      dialog.Banner = Images.Banner;
    
  
    
      
                    
      
      dialog.UserName = "initial user name";
    
  
    
      

 

    
      
                    
      
      dialog.DoNotPersist = true;
    
  
    
      
                    
      
      dialog.ShowSaveCheckBox = true;
    
  
    
      

 

    
      
                    
      
      if (DialogResult.OK == dialog.ShowDialog(this))
    
  
    
      
                    
      
      {
    
  
    
      
            
      
      
                    
      
      // Use credentials wisely...
    
  
    
      
                    
      
      }
    
  
    
      
                
      
      }
    
  
    
      
            
      
      }
    
  
    
      }
    
  


Windows Credential Management with the .net Framework 2.0


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论