Windows客戶端開發--通過CREDENTIAL儲存使用者名稱和密碼
做windows客戶端,尤其是c/s開發,幾乎都要接觸到使用者的登入。需要使用者名稱和密碼,那麼我們往往要對使用者名稱和密碼就行儲存。
方案1:寫入ini配置檔案 用過配置檔案儲存使用者名稱和密碼,密碼肯定是不能實明文了,需要採用一定的加密演算法。 但是,這是最大的麻煩,就是很容易被破解,反加密,得到使用者的密碼。 如何讀取ini檔案,請看:http://blog.csdn.net/wangshubo1989/article/details/47255823
方案2:寫入資料口 可以通過寫入資料庫的方法,比如寫入sqlite。 弊端和寫入ini大差不差,就是容易被破解。
std::string last_name; bool success = accounts_tb_->Get(kLastUserNameSqlKey, &last_name); if (success) { if (!last_name.empty()) { return last_team_from_cache; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
方案3:qt中的QSettings 在qt中,我們可以使用QSettings來儲存使用者名稱和密碼:
const static QString SETTING_ACCOUNT_ID = "account_id";QSettings *settings = new QSettings();settings->setValue(SETTING_ACCOUNT_ID, id);QString id = settings->value(SETTING_ACCOUNT_ID, "" ).toString();
- 1
- 2
- 3
- 4
- 5
方案4:windows系統上的PCREDENTIALW
資料夾: WinCred.h
PCREDENTIALW介紹: The CREDENTIAL structure contains an individual credential. 原型:
typedef struct _CREDENTIAL { DWORD Flags; DWORD Type; LPTSTR TargetName; LPTSTR Comment; FILETIME LastWritten; DWORD CredentialBlobSize; LPBYTE CredentialBlob; DWORD Persist; DWORD AttributeCount; PCREDENTIAL_ATTRIBUTE Attributes; LPTSTR TargetAlias; LPTSTR UserName;} CREDENTIAL, *PCREDENTIAL;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
我們注意關注UserName和CredentialBlob: CredentialBlob Secret data for the credential. The CredentialBlob member can be both read and written.
If the Type member is CRED_TYPE_DOMAIN_PASSWORD, this member contains the plaintext Unicode password for UserName. The CredentialBlob and CredentialBlobSize members do not include a trailing zero character. Also, for CRED_TYPE_DOMAIN_PASSWORD, this member can only be read by the authentication packages. If the Type member is CRED_TYPE_DOMAIN_CERTIFICATE, this member contains the clear test Unicode PIN for UserName. The CredentialBlob and CredentialBlobSize members do not include a trailing zero character. Also, this member can only be read by the authentication packages. If the Type member is CRED_TYPE_GENERIC, this member is defined by the application. Credentials are expected to be portable. Applications should ensure that the data in CredentialBlob is portable. The application defines the byte-endian and alignment of the data in CredentialBlob.
UserName The user name of the account used to connect to TargetName. If the credential Type is CRED_TYPE_DOMAIN_PASSWORD, this member can be either a DomainName\UserName or a UPN. If the credential Type is CRED_TYPE_DOMAIN_CERTIFICATE, this member must be a marshaled certificate reference created by calling CredMarshalCredential with a CertCredential. If the credential Type is CRED_TYPE_GENERIC, this member can be non-NULL, but the credential manager ignores the member. This member cannot be longer than CRED_MAX_USERNAME_LENGTH (513) characters.
CredWrite函式 作用: The CredWrite function creates a new credential or modifies an existing credential in the user’s credential set. 原型:
BOOL CredWrite( _In_ PCREDENTIAL Credential, _In_ DWORD Flags);
- 1
- 2
- 3
- 4
CredRead函式 作用: The CredRead function reads a credential from the user’s credential set. 原型:
BOOL CredRead( _In_ LPCTSTR TargetName, _In_ DWORD Type, _In_ DWORD Flags, _Out_ PCREDENTIAL *Credential);
- 1
- 2
- 3
- 4
- 5
- 6
儲存使用者名稱和密碼
bool SaveAccount(const std::string& username, const std::string& password) { char password_chars[255] = { 0 }; wchar_t username_wstrs[255] = { 0 }; wchar_t target_name_wstrs[1024] = { 0 }; // password strcpy(password_chars, password.c_str()); DWORD cbCreds = 1 + strlen(password_chars); // username std::wstring username_wstr = nbase::UTF8ToUTF16(username); wcscpy(username_wstrs, username_wstr.c_str()); // target name std::wstring target_name_wstr = L"MyApp"; wcscpy(target_name_wstrs, target_name_wstr.c_str()); CREDENTIALW cred = { 0 }; cred.Type = CRED_TYPE_GENERIC; cred.TargetName = target_name_wstrs; cred.CredentialBlobSize = cbCreds; cred.CredentialBlob = (LPBYTE)password_chars; cred.Persist = CRED_PERSIST_LOCAL_MACHINE; cred.UserName = username_wstrs; return ::CredWriteW(&cred, 0);}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
讀取使用者名稱和密碼
bool GetAccount(std::string& username, std::string& password){ wchar_t username_wstrs[255] = { 0 }; wchar_t target_name_wstrs[1024] = { 0 }; // target name std::wstring target_name_wstr = L"MyApp"; PCREDENTIALW pcred; BOOL success = false; do { success = ::CredReadW(target_name_wstr.c_str(), CRED_TYPE_GENERIC, 0, &pcred); if (!success) { break; } username = nbase::UTF16ToUTF8(pcred->UserName); std::string pwd((char*)pcred->CredentialBlob, pcred->CredentialBlobSize); password = pwd; ::CredFree(pcred); return true; } while (0); return false;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27