ADHelper 活动目录用户操作类

using  System;
using  System.DirectoryServices;
 
namespace  SystemFrameworks.Helper
{
     
///
     
/// 活动目录辅助类。封装一系列活动目录操作相关的方法。
     
///
      public   sealed   class  ADHelper
     {
         
///
         
/// 域名
         
///
          private   static   string  DomainName  =   " MyDomain " ;
         
///
         
///  LDAP 地址
         
///
          private   static   string  LDAPDomain  =   " DC=MyDomain,DC=local " ;
         
///
         
///  LDAP绑定路径
         
///
          private   static   string  ADPath  =   " LDAP://brooks.mydomain.local " ;
         
///
         
/// 登录帐号
         
///
          private   static   string  ADUser  =   " Administrator " ;
         
///
         
/// 登录密码
         
///
          private   static   string  ADPassword  =   " password " ;
         
///
         
/// 扮演类实例
         
///
          private   static  IdentityImpersonation impersonate  =   new  IdentityImpersonation(ADUser, ADPassword, DomainName);
 
         
///
         
/// 用户登录验证结果
         
///
          public   enum  LoginResult
         {
              
///
              
/// 正常登录
              
///
              LOGIN_USER_OK  =   0 ,
              
///
              
/// 用户不存在
              
///
              LOGIN_USER_DOESNT_EXIST,
              
///
              
/// 用户帐号被禁用
              
///
              LOGIN_USER_ACCOUNT_INACTIVE,
              
///
              
/// 用户密码不正确
              
///
              LOGIN_USER_PASSWORD_INCORRECT
         }
 
         
///
         
/// 用户属性定义标志
         
///
          public   enum  ADS_USER_FLAG_ENUM
         {
              
///
              
/// 登录脚本标志。如果通过 ADSI LDAP 进行读或写操作时,该标志失效。如果通过 ADSI WINNT,该标志为只读。
              
///
              ADS_UF_SCRIPT  =   0X0001 ,
              
///
              
/// 用户帐号禁用标志
              
///
              ADS_UF_ACCOUNTDISABLE  =   0X0002 ,
              
///
              
/// 主文件夹标志
              
///
              ADS_UF_HOMEDIR_REQUIRED  =   0X0008 ,
              
///
              
/// 过期标志
              
///
              ADS_UF_LOCKOUT  =   0X0010 ,
              
///
              
/// 用户密码不是必须的
              
///
              ADS_UF_PASSWD_NOTREQD  =   0X0020 ,
              
///
              
/// 密码不能更改标志
              
///
              ADS_UF_PASSWD_CANT_CHANGE  =   0X0040 ,
              
///
              
/// 使用可逆的加密保存密码
              
///
              ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED  =   0X0080 ,
              
///
              
/// 本地帐号标志
              
///
              ADS_UF_TEMP_DUPLICATE_ACCOUNT  =   0X0100 ,
              
///
              
/// 普通用户的默认帐号类型
              
///
              ADS_UF_NORMAL_ACCOUNT  =   0X0200 ,
              
///
              
/// 跨域的信任帐号标志
              
///
              ADS_UF_INTERDOMAIN_TRUST_ACCOUNT  =   0X0800 ,
              
///
              
/// 工作站信任帐号标志
              
///
              ADS_UF_WORKSTATION_TRUST_ACCOUNT  =   0x1000 ,
              
///
              
/// 服务器信任帐号标志
              
///
              ADS_UF_SERVER_TRUST_ACCOUNT  =   0X2000 ,
              
///
              
/// 密码永不过期标志
              
///
              ADS_UF_DONT_EXPIRE_PASSWD  =   0X10000 ,
              
///
              
///  MNS 帐号标志
              
///
              ADS_UF_MNS_LOGON_ACCOUNT  =   0X20000 ,
              
///
              
/// 交互式登录必须使用智能卡
              
///
              ADS_UF_SMARTCARD_REQUIRED  =   0X40000 ,
              
///
              
/// 当设置该标志时,服务帐号(用户或计算机帐号)将通过 Kerberos 委托信任
              
///
              ADS_UF_TRUSTED_FOR_DELEGATION  =   0X80000 ,
              
///
              
/// 当设置该标志时,即使服务帐号是通过 Kerberos 委托信任的,敏感帐号不能被委托
              
///
              ADS_UF_NOT_DELEGATED  =   0X100000 ,
              
///
              
/// 此帐号需要 DES 加密类型
              
///
              ADS_UF_USE_DES_KEY_ONLY  =   0X200000 ,
              
///
              
/// 不要进行 Kerberos 预身份验证
              
///
              ADS_UF_DONT_REQUIRE_PREAUTH  =   0X4000000 ,
              
///
              
/// 用户密码过期标志
              
///
              ADS_UF_PASSWORD_EXPIRED  =   0X800000 ,
              
///
              
/// 用户帐号可委托标志
              
///
              ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION  =   0X1000000
         }
 
         
public  ADHelper()
         {
              
//
         }
 
         
#region  GetDirectoryObject
 
         
///
         
/// 获得DirectoryEntry对象实例,以管理员登陆AD
         
///
         
///
          private   static  DirectoryEntry GetDirectoryObject()
         {
              DirectoryEntry entry 
=   new  DirectoryEntry(ADPath, ADUser, ADPassword, AuthenticationTypes.Secure);
              
return  entry;
         }
 
         
///
         
/// 根据指定用户名和密码获得相应DirectoryEntry实体
         
///
         
///
         
///
         
///
          private   static  DirectoryEntry GetDirectoryObject( string  userName,  string  password)
         {
              DirectoryEntry entry 
=   new  DirectoryEntry(ADPath, userName, password, AuthenticationTypes.None);
              
return  entry;
         }
 
         
///
         
///  i.e. /CN=Users,DC=creditsights, DC=cyberelves, DC=Com
         
///
         
///
         
///
          private   static  DirectoryEntry GetDirectoryObject( string  domainReference)
         {
              DirectoryEntry entry 
=   new  DirectoryEntry(ADPath  +  domainReference, ADUser, ADPassword, AuthenticationTypes.Secure);
              
return  entry;
         }
 
         
///
         
/// 获得以UserName,Password创建的DirectoryEntry
         
///
         
///
         
///
         
///
         
///
          private   static  DirectoryEntry GetDirectoryObject( string  domainReference,  string  userName,  string  password)
         {
              DirectoryEntry entry 
=   new  DirectoryEntry(ADPath  +  domainReference, userName, password, AuthenticationTypes.Secure);
              
return  entry;
         }
 
         
#endregion
 
         
#region  GetDirectoryEntry
 
         
///
         
/// 根据用户公共名称取得用户的 对象
         
///
         
/// 用户公共名称
         
/// 如果找到该用户,则返回用户的 对象;否则返回 null
          public   static  DirectoryEntry GetDirectoryEntry( string  commonName)
         {
              DirectoryEntry de 
=  GetDirectoryObject();
              DirectorySearcher deSearch 
=   new  DirectorySearcher(de);
              deSearch.Filter 
=   " (&(&(objectCategory=person)(objectClass=user))(cn= "   +  commonName  +   " )) " ;
              deSearch.SearchScope 
=  SearchScope.Subtree;
 
              
try
              {
                   SearchResult result 
=  deSearch.FindOne();
                   de 
=   new  DirectoryEntry(result.Path);
                   
return  de;
              }
              
catch
              {
                   
return   null ;
              }
         }
 
         
///
         
/// 根据用户公共名称和密码取得用户的 对象。
         
///
         
/// 用户公共名称
         
/// 用户密码
         
/// 如果找到该用户,则返回用户的 对象;否则返回 null
          public   static  DirectoryEntry GetDirectoryEntry( string  commonName,  string  password)
         {
              DirectoryEntry de 
=  GetDirectoryObject(commonName, password);
              DirectorySearcher deSearch 
=   new  DirectorySearcher(de);
              deSearch.Filter 
=   " (&(&(objectCategory=person)(objectClass=user))(cn= "   +  commonName  +   " )) " ;
              deSearch.SearchScope 
=  SearchScope.Subtree;
 
              
try
              {
                   SearchResult result 
=  deSearch.FindOne();
                   de 
=   new  DirectoryEntry(result.Path);
                   
return  de;
              }
              
catch
              {
                   
return   null ;
              }
         }
 
         
///
         
/// 根据用户帐号称取得用户的 对象
         
///
         
/// 用户帐号名
         
/// 如果找到该用户,则返回用户的 对象;否则返回 null
          public   static  DirectoryEntry GetDirectoryEntryByAccount( string  sAMAccountName)
         {
              DirectoryEntry de 
=  GetDirectoryObject();
              DirectorySearcher deSearch 
=   new  DirectorySearcher(de);
              deSearch.Filter 
=   " (&(&(objectCategory=person)(objectClass=user))(sAMAccountName= "   +  sAMAccountName  +   " )) " ;
              deSearch.SearchScope 
=  SearchScope.Subtree;
 
              
try
              {
                   SearchResult result 
=  deSearch.FindOne();
                   de 
=   new  DirectoryEntry(result.Path);
                   
return  de;
              }
              
catch
              {
                   
return   null ;
              }
         }
 
         
///
         
/// 根据用户帐号和密码取得用户的 对象
         
///
         
/// 用户帐号名
         
/// 用户密码
         
/// 如果找到该用户,则返回用户的 对象;否则返回 null
          public   static  DirectoryEntry GetDirectoryEntryByAccount( string  sAMAccountName,  string  password)
         {
              DirectoryEntry de 
=  GetDirectoryEntryByAccount(sAMAccountName);
              
if  (de  !=   null )
              {
                   
string  commonName  =  de.Properties[ " cn " ][ 0 ].ToString();
 
                   
if  (GetDirectoryEntry(commonName, password)  !=   null )
                       
return  GetDirectoryEntry(commonName, password);
                   
else
                       
return   null ;
              }
              
else
              {
                   
return   null ;
              }
         }
 
         
///
         
/// 根据组名取得用户组的 对象
         
///
         
/// 组名
         
///
          public   static  DirectoryEntry GetDirectoryEntryOfGroup( string  groupName)
         {
              DirectoryEntry de 
=  GetDirectoryObject();
              DirectorySearcher deSearch 
=   new  DirectorySearcher(de);
              deSearch.Filter 
=   " (&(objectClass=group)(cn= "   +  groupName  +   " )) " ;
              deSearch.SearchScope 
=  SearchScope.Subtree;
 
              
try
              {
                   SearchResult result 
=  deSearch.FindOne();
                   de 
=   new  DirectoryEntry(result.Path);
                   
return  de;
              }
              
catch
              {
                   
return   null ;
              }
         }
 
         
#endregion
 
         
#region  GetProperty
 
         
///
         
/// 获得指定 指定属性名对应的值
         
///
         
///
         
/// 属性名称
         
/// 属性值
          public   static   string  GetProperty(DirectoryEntry de,  string  propertyName)
         {
              
if (de.Properties.Contains(propertyName))
              {
                   
return  de.Properties[propertyName][ 0 ].ToString() ;
              }
              
else
              {
                   
return   string .Empty;
              }
         }
 
         
///
         
/// 获得指定搜索结果 中指定属性名对应的值
         
///
         
///
         
/// 属性名称
         
/// 属性值
          public   static   string  GetProperty(SearchResult searchResult,  string  propertyName)
         {
              
if (searchResult.Properties.Contains(propertyName))
              {
                   
return  searchResult.Properties[propertyName][ 0 ].ToString() ;
              }
              
else
              {
                   
return   string .Empty;
              }
         }
 
         
#endregion
 
         
///
         
/// 设置指定 的属性值
         
///
         
///
         
/// 属性名称
         
/// 属性值
          public   static   void  SetProperty(DirectoryEntry de,  string  propertyName,  string  propertyValue)
         {
              
if (propertyValue  !=   string .Empty  ||  propertyValue  !=   ""   ||  propertyValue  !=   null )
              {
                   
if (de.Properties.Contains(propertyName))
                   {
                       de.Properties[propertyName][
0 =  propertyValue; 
                   }
                   
else
                   {
                       de.Properties[propertyName].Add(propertyValue);
                   }
              }
         }
 
         
///
         
/// 创建新的用户
         
///
         
/// DN 位置。例如:OU=共享平台 或 CN=Users
         
/// 公共名称
         
/// 帐号
         
/// 密码
         
///
          public   static  DirectoryEntry CreateNewUser( string  ldapDN,  string  commonName,  string  sAMAccountName,  string  password)
         {
              DirectoryEntry entry 
=  GetDirectoryObject();
              DirectoryEntry subEntry 
=  entry.Children.Find(ldapDN);
              DirectoryEntry deUser 
=  subEntry.Children.Add( " CN= "   +  commonName,  " user " );
              deUser.Properties[
" sAMAccountName " ].Value  =  sAMAccountName;
              deUser.CommitChanges();
              ADHelper.EnableUser(commonName);
              ADHelper.SetPassword(commonName, password);
              deUser.Close();
              
return  deUser;
         }
 
         
///
         
/// 创建新的用户。默认创建在 Users 单元下。
         
///
         
/// 公共名称
         
/// 帐号
         
/// 密码
         
///
          public   static  DirectoryEntry CreateNewUser( string  commonName,  string  sAMAccountName,  string  password)
         {
              
return  CreateNewUser( " CN=Users " , commonName, sAMAccountName, password);
         }
 
         
///
         
/// 判断指定公共名称的用户是否存在
         
///
         
/// 用户公共名称
         
/// 如果存在,返回 true;否则返回 false
          public   static   bool  IsUserExists( string  commonName)
         {
              DirectoryEntry de 
=  GetDirectoryObject();
              DirectorySearcher deSearch 
=   new  DirectorySearcher(de);
              deSearch.Filter 
=   " (&(&(objectCategory=person)(objectClass=user))(cn= "   +  commonName  +   " )) " ;        //  LDAP 查询串
              SearchResultCollection results  =  deSearch.FindAll();
 
              
if  (results.Count  ==   0 )
                   
return   false ;
              
else
                   
return   true ;
         }
 
         
///
         
/// 判断用户帐号是否激活
         
///
         
/// 用户帐号属性控制器
         
/// 如果用户帐号已经激活,返回 true;否则返回 false
          public   static   bool  IsAccountActive( int  userAccountControl)
         {
              
int  userAccountControl_Disabled  =  Convert.ToInt32(ADS_USER_FLAG_ENUM.ADS_UF_ACCOUNTDISABLE);
              
int  flagExists  =  userAccountControl  &  userAccountControl_Disabled;
 
              
if  (flagExists  >   0 )
                   
return   false ;
              
else
                   
return   true ;
         }
 
         
///
         
/// 判断用户与密码是否足够以满足身份验证进而登录
         
///
         
/// 用户公共名称
         
/// 密码
         
/// 如能可正常登录,则返回 true;否则返回 false
          public   static  LoginResult Login( string  commonName,  string  password)
         {
              DirectoryEntry de 
=  GetDirectoryEntry(commonName);
 
              
if  (de  !=   null )
              {
                   
//  必须在判断用户密码正确前,对帐号激活属性进行判断;否则将出现异常。
                    int  userAccountControl  =  Convert.ToInt32(de.Properties[ " userAccountControl " ][ 0 ]);
                   de.Close();
 
                   
if  ( ! IsAccountActive(userAccountControl))
                       
return  LoginResult.LOGIN_USER_ACCOUNT_INACTIVE;
 
                   
if  (GetDirectoryEntry(commonName, password)  !=   null )
                       
return  LoginResult.LOGIN_USER_OK;
                   
else
                       
return  LoginResult.LOGIN_USER_PASSWORD_INCORRECT;
              }
              
else
              {
                   
return  LoginResult.LOGIN_USER_DOESNT_EXIST; 
              }
         }
 
         
///
         
/// 判断用户帐号与密码是否足够以满足身份验证进而登录
         
///
         
/// 用户帐号
         
/// 密码
         
/// 如能可正常登录,则返回 true;否则返回 false
          public   static  LoginResult LoginByAccount( string  sAMAccountName,  string  password)
         {
              DirectoryEntry de 
=  GetDirectoryEntryByAccount(sAMAccountName);
                   
              
if  (de  !=   null )
              {
                   
//  必须在判断用户密码正确前,对帐号激活属性进行判断;否则将出现异常。
                    int  userAccountControl  =  Convert.ToInt32(de.Properties[ " userAccountControl " ][ 0 ]);
                   de.Close();
 
                   
if  ( ! IsAccountActive(userAccountControl))
                       
return  LoginResult.LOGIN_USER_ACCOUNT_INACTIVE;
 
                   
if  (GetDirectoryEntryByAccount(sAMAccountName, password)  !=   null )
                       
return  LoginResult.LOGIN_USER_OK;
                   
else
                       
return  LoginResult.LOGIN_USER_PASSWORD_INCORRECT;
              }
              
else
              {
                   
return  LoginResult.LOGIN_USER_DOESNT_EXIST; 
              }
         }
 
         
///
         
/// 设置用户密码,管理员可以通过它来修改指定用户的密码。
         
///
         
/// 用户公共名称
         
/// 用户新密码
          public   static   void  SetPassword( string  commonName,  string  newPassword)
         {
              DirectoryEntry de 
=  GetDirectoryEntry(commonName);
              
              
//  模拟超级管理员,以达到有权限修改用户密码
              impersonate.BeginImpersonate();
              de.Invoke(
" SetPassword " new   object []{newPassword});
              impersonate.StopImpersonate();
 
              de.Close();
         }
 
         
///
         
/// 设置帐号密码,管理员可以通过它来修改指定帐号的密码。
         
///
         
/// 用户帐号
         
/// 用户新密码
          public   static   void  SetPasswordByAccount( string  sAMAccountName,  string  newPassword)
         {
              DirectoryEntry de 
=  GetDirectoryEntryByAccount(sAMAccountName);
 
              
//  模拟超级管理员,以达到有权限修改用户密码
              IdentityImpersonation impersonate  =   new  IdentityImpersonation(ADUser, ADPassword, DomainName);
              impersonate.BeginImpersonate();
              de.Invoke(
" SetPassword " new   object []{newPassword});
              impersonate.StopImpersonate();
 
              de.Close();
         }
 
         
///
         
/// 修改用户密码
         
///
         
/// 用户公共名称
         
/// 旧密码
         
/// 新密码
          public   static   void  ChangeUserPassword ( string  commonName,  string  oldPassword,  string  newPassword)
         {
              
//  to-do: 需要解决密码策略问题
              DirectoryEntry oUser  =  GetDirectoryEntry(commonName);
              oUser.Invoke(
" ChangePassword " new  Object[]{oldPassword, newPassword});
              oUser.Close();
         }
 
         
///
         
/// 启用指定公共名称的用户
         
///
         
/// 用户公共名称
          public   static   void  EnableUser( string  commonName)
         {
              EnableUser(GetDirectoryEntry(commonName));
         }
 
         
///
         
/// 启用指定 的用户
         
///
         
///
          public   static   void  EnableUser(DirectoryEntry de)
         {
              impersonate.BeginImpersonate();
              de.Properties[
" userAccountControl " ][ 0 =  ADHelper.ADS_USER_FLAG_ENUM.ADS_UF_NORMAL_ACCOUNT  |  ADHelper.ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD;
              de.CommitChanges();
              impersonate.StopImpersonate();
              de.Close();
         }
 
         
///
         
/// 禁用指定公共名称的用户
         
///
         
/// 用户公共名称
          public   static   void  DisableUser( string  commonName)
         {
              DisableUser(GetDirectoryEntry(commonName));
         }
 
         
///
         
/// 禁用指定 的用户
         
///
         
///
          public   static   void  DisableUser(DirectoryEntry de)
         {
              impersonate.BeginImpersonate();
              de.Properties[
" userAccountControl " ][ 0 ] = ADHelper.ADS_USER_FLAG_ENUM.ADS_UF_NORMAL_ACCOUNT  |  ADHelper.ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD  |  ADHelper.ADS_USER_FLAG_ENUM.ADS_UF_ACCOUNTDISABLE;
              de.CommitChanges();
              impersonate.StopImpersonate();
              de.Close();
         }
 
         
///
         
/// 将指定的用户添加到指定的组中。默认为 Users 下的组和用户。
         
///
         
/// 用户公共名称
         
/// 组名
          public   static   void  AddUserToGroup( string  userCommonName,  string  groupName)
          {
              DirectoryEntry oGroup 
=  GetDirectoryEntryOfGroup(groupName);
              DirectoryEntry oUser 
=  GetDirectoryEntry(userCommonName);
              
              impersonate.BeginImpersonate();
              oGroup.Properties[
" member " ].Add(oUser.Properties[ " distinguishedName " ].Value);
              oGroup.CommitChanges();
              impersonate.StopImpersonate();
 
              oGroup.Close();
              oUser.Close();
         }
 
         
///
         
/// 将用户从指定组中移除。默认为 Users 下的组和用户。
         
///
         
/// 用户公共名称
         
/// 组名
          public   static   void  RemoveUserFromGroup( string  userCommonName,  string  groupName)
         {
              DirectoryEntry oGroup 
=  GetDirectoryEntryOfGroup(groupName);
              DirectoryEntry oUser 
=  GetDirectoryEntry(userCommonName);
              
              impersonate.BeginImpersonate();
              oGroup.Properties[
" member " ].Remove(oUser.Properties[ " distinguishedName " ].Value);
              oGroup.CommitChanges();
              impersonate.StopImpersonate();
 
              oGroup.Close();
              oUser.Close();
         }
 
     }
 
     
///
     
/// 用户模拟角色类。实现在程序段内进行用户角色模拟。
     
///
      public   class  IdentityImpersonation
     {
         [DllImport(
" advapi32.dll " , SetLastError = true )]
         
public   static   extern   bool  LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,  int  dwLogonType,  int  dwLogonProvider,  ref  IntPtr phToken);
 
         [DllImport(
" advapi32.dll " , CharSet = CharSet.Auto, SetLastError = true )]
         
public   extern   static   bool  DuplicateToken(IntPtr ExistingTokenHandle,  int  SECURITY_IMPERSONATION_LEVEL,  ref  IntPtr DuplicateTokenHandle);
 
         [DllImport(
" kernel32.dll " , CharSet = CharSet.Auto)]
         
public   extern   static   bool  CloseHandle(IntPtr handle);
 
         
//  要模拟的用户的用户名、密码、域(机器名)
          private  String _sImperUsername;
         
private  String _sImperPassword;
         
private  String _sImperDomain;
         
//  记录模拟上下文
          private  WindowsImpersonationContext _imperContext;
         
private  IntPtr _adminToken;
         
private  IntPtr _dupeToken;
         
//  是否已停止模拟
          private  Boolean _bClosed;
 
         
///
         
/// 构造函数
         
///
         
/// 所要模拟的用户的用户名
         
/// 所要模拟的用户的密码
         
/// 所要模拟的用户所在的域
          public  IdentityImpersonation(String impersonationUsername, String impersonationPassword, String impersonationDomain) 
         {
              _sImperUsername 
=  impersonationUsername;
              _sImperPassword 
=  impersonationPassword;
              _sImperDomain 
=  impersonationDomain;
 
              _adminToken 
=  IntPtr.Zero;
              _dupeToken 
=  IntPtr.Zero;
              _bClosed 
=   true ;
         }
 
         
///
         
/// 析构函数
         
///
          ~ IdentityImpersonation() 
         {
              
if ( ! _bClosed) 
              {
                   StopImpersonate();
              }
         }
 
         
///
         
/// 开始身份角色模拟。
         
///
         
///
          public  Boolean BeginImpersonate() 
         {
              Boolean bLogined 
=  LogonUser(_sImperUsername, _sImperDomain, _sImperPassword,  2 0 ref  _adminToken);
                        
              
if ( ! bLogined) 
              {
                   
return   false ;
              }
 
              Boolean bDuped 
=  DuplicateToken(_adminToken,  2 ref  _dupeToken);
 
              
if ( ! bDuped) 
              {
                   
return   false ;
              }
 
              WindowsIdentity fakeId 
=   new  WindowsIdentity(_dupeToken);
              _imperContext 
=  fakeId.Impersonate();
 
              _bClosed 
=   false ;
 
              
return   true ;
         }
 
         
///
         
/// 停止身分角色模拟。
         
///
          public   void  StopImpersonate() 
         {
              _imperContext.Undo();
              CloseHandle(_dupeToken);
              CloseHandle(_adminToken);
              _bClosed 
=   true ;
         }
     }
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值