Android入门第52天-在SharedPreference中使用加密

news2025/1/20 1:43:20

简介

在上一篇中,我们讲了SharedPreference的使用。但是那不是一个生产场景。特别是我们举了一个例子,存放登录信息的例子。这个例子里用户的密码没有加密,比如说在真实的实际生产环境里用户的一些敏感信息或者说是像:用户四要素按照等保3规范以及“个信”法,都是需要加密和脱敏的。所以当碰到这样的“敏感”信息脱敏需求时,我们不可以直接把一个明文存入SharedPreference。因此我们今天会使用MD5来对SharedPreference中存放的信息进行脱敏处理。

下面进入正文。

课程目标

我们依旧延用之前的登录界面,只不过这次我们需要完成下面几个事:

  1. 用户点登录按钮后把信息中的密码使用MD5进行脱敏。此处可以由开发者自行换成自己的加密算法。顺便说一下,在有https保护的情况下我建议这种TO C端的加密使用AES 512位或以上加密就足够了,没必要使用RSA1024位+的算法,又重又无用。如果你要MD5那么记得100次MD5这个结果,否则在一些“MD5彩虹网”输入一个MD5可以在30秒内轻易完成“撞库”成功,因此你100次MD5后,再撞库也是擅不中了;
  2. 把MD5的值存入原来的password字段中去并写入SharedPreference;
  3. 每次应用打开(按模拟器上的开机关机按钮),APP自动从SharedPreference处读出事先存储的内容并以Toast显示;

下面上代码

全代码

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="用户登陆" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="请输入用户名" />

    <EditText
        android:id="@+id/editLoginid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="用户名" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="请输入密码" />

    <EditText
        android:id="@+id/editPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密码"
        android:inputType="textPassword" />

    <Button
        android:id="@+id/buttonLogin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录" />
</LinearLayout>

MD5工具类-MD5.java

package org.mk.android.demo.sp;

import android.util.Log;

import java.security.MessageDigest;


public class MD5 {
    private final static String TAG="DemoSharedPreferenceWithMD5";
    public static String getMD5(String content) {
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(content.getBytes());
            return getHashString(digest);
        } catch (Exception e) {
            Log.e(TAG,e.getMessage(),e);
        }
        return null;
    }

    private static String getHashString(MessageDigest digest) {
        StringBuilder builder = new StringBuilder();
        for (byte b : digest.digest()) {
            builder.append(Integer.toHexString((b >> 4) & 0xf));
            builder.append(Integer.toHexString(b & 0xf));
        }
        return builder.toString();
    }
}

这边多说一句,java security相关包括Base64这些功能请一定不要用sun.misc包一定不要用sun.misc包。这个包已经被废了,一些其它应用如:jdk1.8基础上的一些spring应用用了这些包,后面升JDK11就等着哭吧!你要升,那么要把这个包去了因为在后续jdk版本中这个包已经废了。于是你发觉你要动的东西有一堆,如果不升又面临着各种技术被淘汰,要升付出的代价可能是一半的运行中的生产应用被动到。

SharedPreference的helper类-SharedPreferenceHelper.java

package org.mk.android.demo.sp;

import android.content.Context;
import android.content.SharedPreferences;
import android.widget.Toast;

import java.util.HashMap;
import java.util.Map;

public class SharedPreferenceHelper {

    private final static String SP_TAG="demosp";
    /**
     * 保存数据
     */
    public static void put(Context context, String key, Object obj) {
        SharedPreferences sp = context.getSharedPreferences(SP_TAG, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        if (obj instanceof Boolean) {
            editor.putBoolean(key, (Boolean) obj);
        } else if (obj instanceof Float) {
            editor.putFloat(key, (Float) obj);
        } else if (obj instanceof Integer) {
            editor.putInt(key, (Integer) obj);
        } else if (obj instanceof Long) {
            editor.putLong(key, (Long) obj);
        } else {
            editor.putString(key, (String) obj);
        }
        editor.commit();
    }

    /**
     * 获取指定数据
     */
    public static Object get(Context context, String key, Object defaultObj) {
        SharedPreferences sp = context.getSharedPreferences(SP_TAG, context.MODE_PRIVATE);
        if (defaultObj instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultObj);
        } else if (defaultObj instanceof Float) {
            return sp.getFloat(key, (Float) defaultObj);
        } else if (defaultObj instanceof Integer) {
            return sp.getInt(key, (Integer) defaultObj);
        } else if (defaultObj instanceof Long) {
            return sp.getLong(key, (Long) defaultObj);
        } else if (defaultObj instanceof String) {
            return sp.getString(key, (String) defaultObj);
        }
        return null;
    }

    /**
     * 删除指定数据
     */
    public static void remove(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(SP_TAG, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        editor.commit();
    }

    /**
     * 返回所有键值对
     */
    public static Map<String, ?> getAll(Context context) {
        SharedPreferences sp = context.getSharedPreferences(SP_TAG, context.MODE_PRIVATE);
        Map<String, ?> map = sp.getAll();
        return map;
    }

    /**
     * 删除所有数据
     */
    public static void clear(Context context) {
        SharedPreferences sp = context.getSharedPreferences(SP_TAG, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        editor.commit();
    }

    /**
     * 检查key对应的数据是否存在
     */
    public static boolean contains(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(SP_TAG, context.MODE_PRIVATE);
        return sp.contains(key);
    }

}

MainActivity.java

package org.mk.android.demo.sp;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.util.Map;

public class MainActivity extends AppCompatActivity {
    private EditText editLoginId;
    private EditText editPassword;
    private Button buttonLogin;
    private String strLoginId;
    private String strPassword;
    private Context ctx;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ctx = getApplicationContext();
        bindView();
    }

    private void bindView() {
        editLoginId = (EditText) findViewById(R.id.editLoginid);
        editPassword = (EditText) findViewById(R.id.editPassword);
        buttonLogin = (Button) findViewById(R.id.buttonLogin);
        buttonLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                strLoginId = editLoginId.getText().toString();
                strPassword = editPassword.getText().toString();
                String secPassword = MD5.getMD5(strPassword);
                SharedPreferenceHelper.put(ctx, "loginId", strLoginId);
                SharedPreferenceHelper.put(ctx, "password", secPassword);
                Toast.makeText(ctx, "写SharedPreference成功", Toast.LENGTH_LONG).show();
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        ctx = getApplicationContext();
        String strLoginId = SharedPreferenceHelper.get(ctx, "loginId", "").toString();
        String strPassword = SharedPreferenceHelper.get(ctx, "password", "").toString();
        Toast.makeText(ctx, "从SharedPreference中读到信息LoginId->" + strLoginId + " password->" + strPassword, Toast.LENGTH_LONG).show();
    }
}

这边我们可以看到,在把信息存入SharedPreference前,我们对password这个字段进行了MD5.

运行起来的效果

把信息存入SharedPreference

每次APP“开机”

按我红色箭头所指的APP开/关机按钮。

每次APP“开机”后,请看下部的Toast显示,这个password就是被MD5过了的。

如果你要完成登录校验,只需要把这个MD5值通过API发到后台,在后台直接拿着这个MD5和存储里的密码在拿台拿出来也做同样的MD5,然后把这两个MD值进行比较,结果一致即登录通过。

自己请动一下手试试吧!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/106072.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

磁矢位的引入 工程电磁场 P19

首先我们有恒定磁场的两个方程 为了更方便解决问题&#xff0c;我们引入磁矢位 由此我们可以得到 我们可以得到 我们要确定A&#xff0c;则既需要知道旋度&#xff0c;我们还需要知道散度 如果是均匀媒质&#xff0c;是常数 我们可以得到 我们进行展开可以得到 我们要知道…

索引的底层实现及应用和失效场景

简介 合适的索引能让查询语句性能得到极大的优化&#xff0c;它只是优化业务的一种方式&#xff0c;不能为了建立索引而建立索引。 索引是什么&#xff1f; 索引是一种为了快速查找数据的数据结构&#xff0c;是帮助数据库快速获取数据的 排好序的数据结构 (BTree)。 索引的好…

鸿翼医药备份解决方案:守护医疗数据 携手共克时艰

新冠疫情期间&#xff0c;CT检查成为了明确诊断的重要手段&#xff0c;医学影像科迎来了检测人次的高峰。随着大量的医学影像数据的产生&#xff0c;影像数据占据了医疗数据总数的80-85%&#xff0c;占据了大量的系统存储空间。 我国医学影像数据的年增长率大约为30-40%&#x…

容器云的双活与灾备技术

在多中心多云环境下&#xff0c;可将容器云部署为多活和灾备模式&#xff0c;通过全局负载均衡器实现应用的多中心多活与灾备。容器应用跨数据中心的双活&#xff0c;是将一个应用的不同副本部署到不同的数据中心&#xff0c;如图 1 所示的 Database 应用。 图1 Database应用双…

腾讯天美Java程序员月均20万!掌握这个后,也太香了....

最近在知乎上看到了这样一个热门问答 &#xff08; 图源自知乎&#xff0c;侵删&#xff09; 还附带了一张收入证明&#xff0c;看完后老夫直呼&#xff1a;我滴乖乖&#xff01;太刺激了&#xff01; 虽然这样的高收入只是少数&#xff0c;就像网友说的&#xff0c;不能看做是…

口罩形势下的医院财务管理

过去大多数年轻人一年甚至几年都不需要去医院&#xff0c;但是近三年的口罩带给人们的不便&#xff0c;使得医院一号难求&#xff0c;在这种新的形势下&#xff0c;医院财务管理也成为重要的改革对象财务管理是医院经济工作的核心。 医院所有的经营决策都必须以医院财务核算为…

代码随想录Day57|647.回文子串、516.最长回文子序列、动态规划总结篇

文章目录647.回文子串516.最长回文子序列动态规划总结篇647.回文子串 文章讲解&#xff1a;代码随想录 (programmercarl.com) 题目链接&#xff1a; 题目&#xff1a; 给定一个字符串&#xff0c;你的任务是计算这个字符串中有多少个回文子串。 具有不同开始位置或结束位置…

企业如何在工作中应用知识管理?

伴随着知识经济时代的兴起&#xff0c;企业的经营管理模式发生了新的变革。这种变革主要体现在管理方式由传统的工业生产经营转向了创新的知识经济管理和知识管理&#xff08;KnowledgeManagement, KM)&#xff0c;通过技术创新、高技术领域的探索&#xff0c;以打破制约产业技…

附录2-上传自己的包

目录 1 Node中包的规范 2 创建包 2.1 package.json 2.2 内容部分 2.2.1 格式化时间 handle_date.js 2.2.2 转义/还原 HTML handle_html.js 2.2.3 index.js 2.2.4 测试功能 2.3 说明文档 3 发布包 3.1 注册账号 3.2 登录账号 3.3 上传 4 删除包 4.…

能源管理系统与能源管理平台|瑜岿科技

构建“以新能源为主体的新型电力系统”。众所周知&#xff0c;随着新能源大规模接入&#xff0c;电力系统将呈现显著的“双侧随机性”和“双峰双高”的“三双”特征&#xff0c;为保证电力系统安全稳定高效运行&#xff0c;必须加速推进源网荷储一体化和多能互补发展&#xff0…

790. 多米诺和托米诺平铺(难度:中等)

题目链接&#xff1a;https://leetcode.cn/problems/domino-and-tromino-tiling/ 题目描述&#xff1a; 有两种形状的瓷砖&#xff1a;一种是 2 x 1 的多米诺形&#xff0c;另一种是形如 “L” 的托米诺形。两种形状都可以旋转。 给定整数 n &#xff0c;返回可以平铺 2 x n 的…

使用 Webpack 从 0 到 1 构建 Vue3 项目

目录 1. 初始化项目结构 2. 安装 webpack&#xff0c;补充智能提示 3. 初步编写 webpack.config.js 4. 配置 运行 / 打包 命令&#xff0c;首次打包项目 5. 添加 Vue 及相关配置 6. 增加 删除上次打包文件 的配置 7. 在 webpack 中&#xff0c;配置别名 &#xff0c;替换…

设计模型-工厂方法模式

1、什么是工厂方法 工厂方法模式&#xff08;Factory Method&#xff09;&#xff0c;又称多态性工厂模式&#xff0c;属于设计模式三大分类中的创建型模式&#xff0c;作为抽象工厂模式的孪生兄弟&#xff0c;工厂方法模式定义了一个创建对象的接口&#xff0c;但由子类决定要…

【Quarkus技术系列】「序章」打造基于Quarkus的云原生微服务框架实践的理论知识基础

前提介绍 本系列文章主要讲解如何基于Quarkus技术搭建和开发“专为Kubernetes而优化的Java微服务框架”的入门和实践&#xff0c;你将会学习到如何搭建Quarkus微服务脚环境及脚手架&#xff0c;开发Quarkus的端点服务&#xff0c;系统和应用层级的配置介绍与Quarkus的编程模型…

String类介绍

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一.String类的简单解释二.String类的方法介绍2.1 字符串的声明2.2 字符串的比较第一种比较方法第二种的比较方式第三种比较方式第四种比较的方式2.3字符串的查找…

架构师必读 —— 逻辑模型(12)

头脑风暴的5项原则 为了得出更好的想法&#xff0c;进行发散思维是很重要的&#xff0c;巧妙地运 用头脑风暴来尽情地发散吧&#xff01;头脑风暴的秘诀就是自由想象。如果因为害怕被骂而怯于表达自己的想法&#xff0c;或者不好意思在人前发言&#xff0c;好不容易想到的点子也…

6.npm

目录 1 下载包 2 下载包非最新的版本 3 package.json 4 一次安装多个包 5 删除 node_modules 6 一次安装项目中的所有包 7 卸载包 8 将包放入devDependencies中 9 换源 9.1 手动换源 9.2 工具换源 10 全局下载 10.1 下载与卸载 10.2 一些常用的全局…

QUIC协议

一 简介 QUIC(Quick UDP Internet Connection)是Google提出的一个基于UDP的传输协议&#xff0c;因其高效的传输效率和多路并发的能力&#xff0c;已经成为下一代互联网协议HTTP/3的底层传输协议。除了应用于Web领域&#xff0c;它的优势同样适用于一些通用的需要低延迟、高吞…

Android入门第53天-在Android手机里使用SQLite内嵌式数据库

介绍 Android内带SQLite内嵌式数据库了。这对于我们存储一些更复杂的结构化数据带来了极大的便利。比如说我们要存储应用内的常用联系人&#xff0c;购物车暂存信息&#xff0c;常量。必竟从xml或者是json里取数据都没有一条Select语句来得简单。 SQLite常用有五种数据类型: …

第04讲:Redis消息的发布和订阅

一、什么是消息的发布和订阅 Redis 发布订阅 (pub/sub) 是一种消息通信模式&#xff1a;发送者 (pub) 发送消息&#xff0c;订阅者 (sub) 接收消息。 Tip&#xff1a;Redis 客户端&#xff08;redis-cli&#xff09;可以订阅任意数量的频道。 二、Redis的发布和订阅的原理 客…