欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Token安全存儲的幾種方式小結

 更新時間:2025年04月18日 10:21:42   作者:一一Null  
在現代 Web 應用中,身份認證與授權是確保系統(tǒng)安全性的重要部分,Token被廣泛應用,作為實現身份認證的主要方式,然而,如何安全地存儲這些 Token,是每個開發(fā)者在構建前端應用時必須考慮的問題,本文將深入探討Token安全存儲的幾種方式,需要的朋友可以參考下

1. EncryptedSharedPreferences

EncryptedSharedPreferences 是一個開源庫,用于對 SharedPreferences 進行加密存儲,提供了更高的安全性。

示例代碼

// 創(chuàng)建 EncryptedSharedPreferences
MasterKeys.KeyPair keyPair = MasterKeys.generateKeyPair(context, MasterKeys.AES256_GCM_SPEC);
String keyAlias = keyPair.getAlias();

EncryptedSharedPreferences encryptedSharedPreferences = EncryptedSharedPreferences.create(
        context,
        "encrypted_prefs",
        keyAlias,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);

// 存儲 Token
SharedPreferences.Editor editor = encryptedSharedPreferences.edit();
editor.putString("token", token);
editor.apply();

// 獲取 Token
String token = encryptedSharedPreferences.getString("token", null);

2. SQLCipher

SQLCipher 是一個開源庫,用于對 SQLite 數據庫進行加密存儲,適用于需要更高安全性的場景。

示例代碼

// 初始化 SQLCipher 數據庫
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(
        new File(context.getFilesDir(), "encrypted.db"),
        "password", // 數據庫密碼
        null
);

// 創(chuàng)建表并存儲 Token
db.execSQL("CREATE TABLE IF NOT EXISTS tokens (token TEXT)");
db.execSQL("INSERT INTO tokens (token) VALUES (?)", new Object[]{token});
db.close();

3.使用 Android Keystore加密后存儲

Keystore 提供了硬件級別的加密保護,即使設備被 Root,也很難獲取存儲在 Keystore 中的密鑰。
非常適合存儲 Token、密碼等敏感信息。

不過使用 Keystore 比較復雜,需要生成密鑰對、加密和解密數據等操作。而加密和解密操作會帶來一定的性能開銷。

示例代碼

1. 生成密鑰對

在應用首次啟動時,生成一個密鑰對并存儲在 Keystore 中。

import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Base64;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;

public class KeystoreManager {
    private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
    private static final String KEY_ALIAS = "myAppKeyAlias";
    private static final String ENCRYPTION_ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;
    private static final String ENCRYPTION_BLOCK_MODE = KeyProperties.BLOCK_MODE_GCM;
    private static final String ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_NONE;
    private static final String ENCRYPTION_TRANSFORMATION = ENCRYPTION_ALGORITHM + "/"
            + ENCRYPTION_BLOCK_MODE + "/" + ENCRYPTION_PADDING;

    private KeyStore keyStore;

    public KeystoreManager() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
        keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
        keyStore.load(null);
    }

    public void generateKey() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER);
        keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_ALIAS,
                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(ENCRYPTION_BLOCK_MODE)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build());
        keyGenerator.generateKey();
    }

    public byte[] encryptData(String data) throws Exception {
        Cipher cipher = Cipher.getInstance(ENCRYPTION_TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
        return cipher.doFinal(data.getBytes());
    }

    public String decryptData(byte[] encryptedData) throws Exception {
        Cipher cipher = Cipher.getInstance(ENCRYPTION_TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey());
        return new String(cipher.doFinal(encryptedData));
    }

    private SecretKey getSecretKey() throws UnrecoverableEntryException, KeyStoreException {
        return (SecretKey) keyStore.getKey(KEY_ALIAS, null);
    }
}

2. 使用 KeystoreManager

在你的應用中,使用 KeystoreManager 來存儲和讀取 Token。

import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;

import java.io.IOException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        try {
            KeystoreManager keystoreManager = new KeystoreManager();
            // 生成密鑰對(只需在首次啟動時調用一次)
            keystoreManager.generateKey();

            // 加密 Token
            String accessToken = "your_access_token_here";
            byte[] encryptedAccessToken = keystoreManager.encryptData(accessToken);
            
			//存儲請參考下述的幾種方式
			
            // 解密 Token
            String decryptedAccessToken = keystoreManager.decryptData(encryptedAccessToken);

            Log.d(TAG, "Encrypted Token: " + Base64.encodeToString(encryptedAccessToken, Base64.DEFAULT));
            Log.d(TAG, "Decrypted Token: " + decryptedAccessToken);
        } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException | UnrecoverableEntryException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
    }
}

代碼說明

  1. 生成密鑰對

    • 使用 KeyGenParameterSpec 定義密鑰的屬性。
    • 使用 KeyGenerator 生成密鑰對并存儲在 Keystore 中。
  2. 加密數據

    • 使用 Cipher 對數據進行加密。
    • 返回加密后的字節(jié)數組。
  3. 解密數據

    • 使用 Cipher 對加密數據進行解密。
    • 返回解密后的字符串。
  4. 存儲和讀取 Token

    • 將加密后的 Token 存儲在應用的私有目錄中(例如 SharedPreferences 或文件系統(tǒng))。
    • 需要時,讀取加密數據并解密。

安全性建議

  1. 密鑰管理:確保密鑰的生成和使用過程安全,避免密鑰泄露。
  2. 存儲加密數據:將加密后的 Token 存儲在應用的私有目錄中,避免被其他應用訪問。
  3. 錯誤處理:在實際應用中,需要對各種異常情況進行處理,確保應用的穩(wěn)定性和安全性。

加密后的幾種存儲方式

1. 加密后采用 SharedPreferences存儲

SharedPreferences 是 Android 中一種輕量級的存儲方式,適合存儲少量的鍵值對數據。你可以將加密后的 Token 存儲到 SharedPreferences 中。

// 存儲加密后的 Token 到 SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("MyAppPreferences", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("encryptedToken", Base64.encodeToString(encryptedAccessToken, Base64.DEFAULT));
editor.apply();

從 SharedPreferences 中讀取時:

SharedPreferences sharedPreferences = getSharedPreferences("MyAppPreferences", MODE_PRIVATE);
String encryptedToken = sharedPreferences.getString("encryptedToken", null);
if (encryptedToken != null) {
    byte[] encryptedAccessToken = Base64.decode(encryptedToken, Base64.DEFAULT);
    // 然后可以對 encryptedAccessToken 進行解密等操作
}

2. 加密后采用SQLite數據庫存儲

如果應用中有數據庫(如 SQLite),也可以將加密后的 Token 存儲到數據庫中。這種方式適合需要結構化存儲的場景。

1. TokenDatabaseHelper 類

以下是 TokenDatabaseHelper 類的完整代碼,用于創(chuàng)建和管理 SQLite 數據庫:

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class TokenDatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "token.db";
    private static final int DATABASE_VERSION = 1;
    private static final String TABLE_TOKENS = "tokens";
    private static final String COLUMN_ID = "id";
    private static final String COLUMN_TOKEN = "token";

    public TokenDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String createTable = "CREATE TABLE " + TABLE_TOKENS + "("
                + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + COLUMN_TOKEN + " TEXT" + ")";
        db.execSQL(createTable);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_TOKENS);
        onCreate(db);
    }

    public void saveToken(String token) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(COLUMN_TOKEN, token);
        db.insert(TABLE_TOKENS, null, values);
        db.close();
    }

    public String getToken() {
        String token = null;
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.query(TABLE_TOKENS, new String[]{COLUMN_TOKEN}, null, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            token = cursor.getString(cursor.getColumnIndex(COLUMN_TOKEN));
        }
        cursor.close();
        db.close();
        return token;
    }
}

2. MainActivity 中的實現

在 MainActivity 中,我們將使用 TokenDatabaseHelper 來存儲和讀取加密后的 Token。

以下是完整的代碼:

import android.os.Bundle;
import android.util.Base64;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;

import java.io.IOException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private TokenDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化數據庫幫助類
        dbHelper = new TokenDatabaseHelper(this);

        try {
            KeystoreManager keystoreManager = new KeystoreManager();
            // 生成密鑰對(只需在首次啟動時調用一次)
            keystoreManager.generateKey();

            // 加密 Token
            String accessToken = "your_access_token_here";
            byte[] encryptedAccessToken = keystoreManager.encryptData(accessToken);

            // 將加密后的 Token 存儲到數據庫
            String encodedToken = Base64.encodeToString(encryptedAccessToken, Base64.DEFAULT);
            dbHelper.saveToken(encodedToken);

            // 從數據庫中讀取 Token
            String retrievedToken = dbHelper.getToken();
            if (retrievedToken != null) {
                byte[] retrievedEncryptedToken = Base64.decode(retrievedToken, Base64.DEFAULT);
                // 解密 Token
                String decryptedAccessToken = keystoreManager.decryptData(retrievedEncryptedToken);
                Log.d(TAG, "Decrypted Token: " + decryptedAccessToken);
            }
        } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException | UnrecoverableEntryException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
    }
}

3. 代碼說明

  1. 加密和存儲 Token

    • 使用 KeystoreManager 加密 Token。
    • 將加密后的 Token(Base64 編碼)存儲到 SQLite 數據庫中。
  2. 讀取和解密 Token

    • 從數據庫中讀取加密后的 Token。
    • 解密 Token 并打印出來。
  3. TokenDatabaseHelper

    • 提供了 saveToken 和 getToken 方法,分別用于存儲和讀取 Token 數據。

4. 注意事項

  • 確保 KeystoreManager 類的 generateKey、encryptData 和 decryptData 方法實現正確。
  • 數據庫的 COLUMN_TOKEN 字段存儲的是 Base64 編碼后的加密數據,確保在存儲和讀取時正確處理編碼和解碼。
  • 如果需要支持多條 Token 數據,可以在 getToken 方法中添加邏輯,例如按時間戳排序或指定特定的 Token。

3. 加密后采用內部文件存儲

如果 Token 數據較大,或者需要更安全的存儲方式,可以將其存儲到內部存儲中。內部存儲是私有的,其他應用無法訪問。

// 存儲到內部存儲
File file = new File(getFilesDir(), "encryptedToken.txt");
FileOutputStream fos = new FileOutputStream(file);
fos.write(encryptedAccessToken);
fos.close();

從內部存儲中讀取時:

File file = new File(getFilesDir(), "encryptedToken.txt");
FileInputStream fis = new FileInputStream(file);
byte[] encryptedAccessToken = new byte[(int) file.length()];
fis.read(encryptedAccessToken);
fis.close();

4. 云存儲服務

如果需要跨設備同步 Token,可以考慮使用云存儲服務,如 Firebase、Dropbox 等。

示例代碼(使用 Firebase)

// 初始化 Firebase 數據庫
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference tokensRef = database.getReference("tokens");

// 存儲 Token
tokensRef.child("userToken").setValue(token);

// 獲取 Token
tokensRef.child("userToken").addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        String token = dataSnapshot.getValue(String.class);
        // 使用 Token
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // 處理錯誤
    }
});

總結

  • EncryptedSharedPreferences:提供加密的 SharedPreferences,適合存儲少量敏感數據。
  • SQLCipher:提供加密的 SQLite 數據庫,適合需要更高安全性的場景。
  • SQLite 數據庫:適合存儲結構化數據,支持復雜查詢。建議先加密在存儲。
  • 文件存儲:適合存儲簡單的文本數據,確保文件權限為 MODE_PRIVATE。建議先加密在存儲。
  • SharedPreferences:適合存儲少量數據。建議先加密在存儲。
  • 云存儲服務:適合跨設備同步數據,但需要依賴第三方服務。

以上就是Token安全存儲的幾種方式小結的詳細內容,更多關于Token安全存儲方式的資料請關注腳本之家其它相關文章!

相關文章

  • Mybatis-Plus?CRUD操作方法

    Mybatis-Plus?CRUD操作方法

    通用?Service?CRUD?封裝?IService?接口,進一步封裝?CRUD?采用?get?查詢、remove?刪除?、list?查詢集合、page?分頁的前綴命名方式區(qū)分?Mapper?層避免混淆,這篇文章主要介紹了Mybatis-Plus?CRUD的相關知識,需要的朋友可以參考下
    2023-10-10
  • MyBatis中特殊符號的轉義

    MyBatis中特殊符號的轉義

    編寫SQL中會用到<,>,,>= 等,但是在mybatis中不可以這么寫,與xml文件的元素沖突,所以需要轉義,本文主要介紹了MyBatis中特殊符號的轉義,主要介紹了兩種轉義方式,感興趣的可以了解一下
    2024-01-01
  • Java設計模式中的門面模式詳解

    Java設計模式中的門面模式詳解

    門面模式又叫外觀模式(Facade Pattern),主要用于隱藏系統(tǒng)的復雜性,并向客戶端提供了一個客戶端可以訪問系統(tǒng)的接口,本文通過實例代碼給大家介紹下java門面模式的相關知識,感興趣的朋友一起看看吧
    2022-09-09
  • MyBatis使用動態(tài)SQL標簽的小陷阱

    MyBatis使用動態(tài)SQL標簽的小陷阱

    MyBatis是一個支持普通SQL查詢,存儲過程和高級映射的優(yōu)秀持久層框架,MyBatis越來越受大家的喜愛了。下面給大家分享MyBatis使用動態(tài)SQL標簽的小陷阱,感興趣的朋友一起看看吧
    2016-10-10
  • mybatis中的延遲加載類型及設定詳解

    mybatis中的延遲加載類型及設定詳解

    這篇文章主要介紹了mybatis中的延遲加載類型及設定詳解,MyBatis中的延遲加載,也稱為懶加載,是指在進行關聯查詢時,按照設置延遲規(guī)則推遲對關聯對象的select查詢,延遲加載可以有效的減少數據庫壓力,需要的朋友可以參考下
    2023-10-10
  • Mybatis一對多與多對一查詢處理詳解

    Mybatis一對多與多對一查詢處理詳解

    這篇文章主要給大家介紹了關于Mybatis一對多與多對一查詢處理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • Java解析微信獲取手機號信息的示例步驟

    Java解析微信獲取手機號信息的示例步驟

    在微信中,用戶手機號的獲取通常是通過微信小程序的getPhoneNumber接口來實現的,下面通過一個基于Java的示例,展示了如何接收并解密從微信小程序傳遞過來的加密手機號信息,感興趣的朋友一起看看吧
    2024-06-06
  • Spring Boot的FailureAnalyzer機制及如何解救應用啟動危機

    Spring Boot的FailureAnalyzer機制及如何解救應用啟動危機

    本文探討了FailureAnalyzer工具,它不僅能幫助我們快速識別和處理代碼中的錯誤,還能極大地提升我們的開發(fā)效率,通過詳細的實例分析,我們了解了FailureAnalyzer如何通過自定義邏輯應對不同類型的異常,讓程序員能夠更好地定位問題并迅速找到解決方案,感興趣的朋友一起看看吧
    2025-01-01
  • Java使用Swing實現一個模擬電腦計算器

    Java使用Swing實現一個模擬電腦計算器

    Java Swing 是一個用于創(chuàng)建 Java GUI(圖形用戶界面)的框架,它提供了一系列的 GUI 組件和工具,可以用于創(chuàng)建桌面應用程序,包括按鈕、文本框、標簽、表格等等,本文給大家介紹了Java使用Swing實現一個模擬計算器,感興趣的同學可以自己動手嘗試一下
    2024-05-05
  • springboot的@Value中#和$區(qū)別詳解

    springboot的@Value中#和$區(qū)別詳解

    這篇文章主要介紹了springboot的@Value中#和$區(qū)別詳解,@Value注解的作用主要可以給屬性直接賦值、也可以讀取配置文件中的值給屬性賦值,需要的朋友可以參考下
    2023-11-11

最新評論