我正在创建一个使用用户名/密码连接到服务器的应用程序,我想启用“保存密码”选项,这样用户就不必在每次应用程序启动时输入密码。

我试图用共享偏好来做,但不确定这是否是最好的解决方案。

我很感激任何关于如何在Android应用程序中存储用户值/设置的建议。


当前回答

共享首选项是存储应用程序数据的最简单方法。但任何人都可以通过应用程序管理器清除我们共享的首选项数据。所以我不认为它对我们的应用是完全安全的。

其他回答

您需要使用sqlite,安全工具来存储密码。 下面是最好的例子,它存储密码——passwordsafe。 这是来源和解释的链接 http://code.google.com/p/android-passwordsafe/

这个答案是基于Mark建议的方法。创建EditTextPreference类的自定义版本,它在视图中看到的纯文本和存储在首选项存储中的密码的加密版本之间来回转换。

正如大多数在这篇文章中回答问题的人所指出的,这不是一种非常安全的技术,尽管安全程度在一定程度上取决于所使用的加密/解密代码。但它相当简单和方便,并将阻止大多数随意窥探。

下面是自定义EditTextPreference类的代码:

package com.Merlinia.OutBack_Client;

import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.util.Base64;

import com.Merlinia.MEncryption_Main.MEncryptionUserPassword;


/**
 * This class extends the EditTextPreference view, providing encryption and decryption services for
 * OutBack user passwords. The passwords in the preferences store are first encrypted using the
 * MEncryption classes and then converted to string using Base64 since the preferences store can not
 * store byte arrays.
 *
 * This is largely copied from this article, except for the encryption/decryption parts:
 * https://groups.google.com/forum/#!topic/android-developers/pMYNEVXMa6M
 */
public class EditPasswordPreference  extends EditTextPreference {

    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context) {
        super(context);
    }


    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
    }


    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context, AttributeSet attributeSet, int defaultStyle) {
        super(context, attributeSet, defaultStyle);
    }


    /**
     * Override the method that gets a preference from the preferences storage, for display by the
     * EditText view. This gets the base64 password, converts it to a byte array, and then decrypts
     * it so it can be displayed in plain text.
     * @return  OutBack user password in plain text
     */
    @Override
    public String getText() {
        String decryptedPassword;

        try {
            decryptedPassword = MEncryptionUserPassword.aesDecrypt(
                     Base64.decode(getSharedPreferences().getString(getKey(), ""), Base64.DEFAULT));
        } catch (Exception e) {
            e.printStackTrace();
            decryptedPassword = "";
        }

        return decryptedPassword;
    }


    /**
     * Override the method that gets a text string from the EditText view and stores the value in
     * the preferences storage. This encrypts the password into a byte array and then encodes that
     * in base64 format.
     * @param passwordText  OutBack user password in plain text
     */
    @Override
    public void setText(String passwordText) {
        byte[] encryptedPassword;

        try {
            encryptedPassword = MEncryptionUserPassword.aesEncrypt(passwordText);
        } catch (Exception e) {
            e.printStackTrace();
            encryptedPassword = new byte[0];
        }

        getSharedPreferences().edit().putString(getKey(),
                                          Base64.encodeToString(encryptedPassword, Base64.DEFAULT))
                .commit();
    }


    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        if (restoreValue)
            getEditText().setText(getText());
        else
            super.onSetInitialValue(restoreValue, defaultValue);
    }
}

这显示了如何使用它-这是驱动首选项显示的“items”文件。注意,它包含三个普通EditTextPreference视图和一个自定义EditPasswordPreference视图。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <EditTextPreference
        android:key="@string/useraccountname_key"
        android:title="@string/useraccountname_title"
        android:summary="@string/useraccountname_summary"
        android:defaultValue="@string/useraccountname_default"
        />

    <com.Merlinia.OutBack_Client.EditPasswordPreference
        android:key="@string/useraccountpassword_key"
        android:title="@string/useraccountpassword_title"
        android:summary="@string/useraccountpassword_summary"
        android:defaultValue="@string/useraccountpassword_default"
        />

    <EditTextPreference
        android:key="@string/outbackserverip_key"
        android:title="@string/outbackserverip_title"
        android:summary="@string/outbackserverip_summary"
        android:defaultValue="@string/outbackserverip_default"
        />

    <EditTextPreference
        android:key="@string/outbackserverport_key"
        android:title="@string/outbackserverport_title"
        android:summary="@string/outbackserverport_summary"
        android:defaultValue="@string/outbackserverport_default"
        />

</PreferenceScreen>

至于实际的加密/解密,留给读者练习。我目前正在使用基于本文的一些代码http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/,尽管键和初始化向量的值不同。

首先,我认为用户的数据不应该存储在手机上,如果必须将数据存储在手机上的某个地方,它应该在应用程序的私有数据中加密。用户凭证的安全性应该是应用程序的优先级。

敏感数据必须安全存储,否则就不存储。在设备丢失或恶意软件感染的情况下,不安全存储的数据可能会受到损害。

共享首选项是存储应用程序数据的最简单方法。但任何人都可以通过应用程序管理器清除我们共享的首选项数据。所以我不认为它对我们的应用是完全安全的。

您还可以查看这个小库,其中包含您提到的功能。

https://github.com/kovmarci86/android-secure-preferences

它与这里的其他一些方法类似。希望会有所帮助:)