Android登录验证教程:正确获取用户输入与安全实践

Android登录验证教程:正确获取用户输入与安全实践

本教程详细指导如何在android应用中构建一个基础的登录表单,并重点纠正了在用户输入验证中常见的逻辑错误,即过早地获取edittext内容。同时,文章强调了在实际开发中避免硬编码用户名和密码的关键安全实践,以确保应用的健壮性和安全性。

1. 构建基础登录界面

一个标准的Android登录界面通常包含用户名输入框、密码输入框和一个登录按钮。以下是使用ConstraintLayout构建这些UI元素的XML布局代码示例:

在上述布局中:

etUsername 用于输入用户名,android:inputType=”textPersonName” 提示系统提供适合人名的键盘。etPassword 用于输入密码,android:inputType=”textPassword” 会将输入内容显示为星号或圆点,保护用户隐私。btnLogin 是触发登录操作的按钮。android:hint 属性为输入框提供占位符文本,提升用户体验。

2. 登录逻辑实现与常见错误分析

在Activity中处理登录逻辑时,我们需要获取用户在EditText中输入的内容,并与预设的凭证进行比较。然而,一个常见的错误是过早地获取EditText的内容。

错误的代码示例:

public class MainActivity extends AppCompatActivity {    private Button btnLogin;    private EditText etUsername;    private EditText etPassword;    String username = "bartul"; // 预设用户名    String password = "kalinic"; // 预设密码    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btnLogin = findViewById(R.id.btnLogin);        etUsername = findViewById(R.id.etUsername);        etPassword = findViewById(R.id.etPassword);        // 错误:在onCreate中过早地获取输入        // 此时EditText通常是空的,因此user和pass变量会是空字符串        String user = etUsername.getText().toString();        String pass = etPassword.getText().toString();        btnLogin.setOnClickListener(new View.OnClickListener(){            @Override            public void onClick(View view) {                // 这里的验证逻辑将使用onCreate中获取到的空字符串user和pass                // 导致即使输入正确,也会被判断为错误                if(!user.equals(username) || !pass.equals(password)) {                    Toast.makeText(getApplicationContext(), "Wrong username or password entered!", Toast.LENGTH_SHORT).show();                    etUsername.setText("");                    etPassword.setText("");                }                else {                    Intent intent = new Intent(MainActivity.this, MiNoteMenuActivity.class);                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);                    startActivity(intent);                }            }        });    }}

错误分析:

上述代码的问题在于,String user = etUsername.getText().toString(); 和 String pass = etPassword.getText().toString(); 这两行代码在 onCreate 方法中执行。onCreate 是Activity生命周期中的一个阶段,此时UI组件刚刚被创建并加载,但用户尚未有机会在 EditText 中输入任何内容。因此,etUsername 和 etPassword 几乎总是返回空字符串。

当用户点击登录按钮时,onClick 方法中用于比较的 user 和 pass 变量仍然是 onCreate 时获取到的空字符串,而不是用户实际输入的内容。这导致无论用户输入什么,验证逻辑都会将用户输入与空字符串进行比较,从而错误地判断为“用户名或密码错误”。

3. 修正登录逻辑

要正确地获取用户输入,必须在用户点击登录按钮时,即在 OnClickListener 的 onClick 方法内部,实时地从 EditText 中读取当前内容。

闪念贝壳 闪念贝壳

闪念贝壳是一款AI 驱动的智能语音笔记,随时随地用语音记录你的每一个想法。

闪念贝壳 218 查看详情 闪念贝壳

修正后的Java代码:

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 androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {    private Button btnLogin;    private EditText etUsername;    private EditText etPassword;    // 预设的用户名和密码,仅用于演示。    // 在实际生产环境中,请勿将敏感信息硬编码。    String predefinedUsername = "bartul";    String predefinedPassword = "kalinic";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // 初始化UI组件        btnLogin = findViewById(R.id.btnLogin);        etUsername = findViewById(R.id.etUsername);        etPassword = findViewById(R.id.etPassword);        // 设置登录按钮的点击监听器        btnLogin.setOnClickListener(new View.OnClickListener(){            @Override            public void onClick(View view) {                // 正确:在点击按钮时获取用户输入,确保获取的是最新内容                String enteredUsername = etUsername.getText().toString();                String enteredPassword = etPassword.getText().toString();                // 执行验证逻辑                if(!enteredUsername.equals(predefinedUsername) || !enteredPassword.equals(predefinedPassword)) {                    // 验证失败:显示Toast提示,并清空输入框                    Toast.makeText(getApplicationContext(), "用户名或密码错误!", Toast.LENGTH_SHORT).show();                    etUsername.setText("");                    etPassword.setText("");                }                else {                    // 验证成功:显示Toast提示,并跳转到下一个Activity                    Toast.makeText(getApplicationContext(), "登录成功!", Toast.LENGTH_SHORT).show();                    Intent intent = new Intent(MainActivity.this, MiNoteMenuActivity.class);                    // 设置Intent标志,清除任务栈中所有Activity并启动新Activity                    // 这样用户在下一个Activity按返回键时不会回到登录界面                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);                    startActivity(intent);                    // 如果希望彻底销毁当前Activity,可以调用finish()                    // finish();                }            }        });    }}

修正后的逻辑说明:

实时获取输入:将 etUsername.getText().toString() 和 etPassword.getText().toString() 的调用移至 onClick 方法内部。这意味着每次用户点击登录按钮时,程序都会从输入框中读取最新的、用户实际输入的内容。验证逻辑:使用 equals() 方法比较用户输入的 enteredUsername 和 enteredPassword 与预设的 predefinedUsername 和 predefinedPassword。如果任一凭证不匹配 (!enteredUsername.equals(…) || !enteredPassword.equals(…)),则显示一个 Toast 提示错误信息,并清空输入框,以便用户重新输入。如果所有凭证都匹配,则显示登录成功 Toast,并通过 Intent 跳转到 MiNoteMenuActivity。页面跳转:Intent 用于在Android组件之间传递信息并启动新的组件。new Intent(MainActivity.this, MiNoteMenuActivity.class) 创建了一个从当前Activity (MainActivity) 跳转到目标Activity (MiNoteMenuActivity) 的意图。intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) 是一个重要的设置。它指示系统清除当前任务栈中的所有Activity,并为 MiNoteMenuActivity 创建一个新的任务。这意味着一旦用户登录成功并进入 MiNoteMenuActivity,他们将无法通过按返回键回到登录界面,因为登录界面已经被销毁。

4. 安全实践与注意事项

虽然上述修正解决了登录逻辑问题,但在实际应用开发中,硬编码用户名和密码是一种极不安全的做法。

安全风险:

代码泄露:应用的APK文件可以被反编译,攻击者很容易从中提取出硬编码的用户名和密码。难以维护:如果需要更改凭证,必须发布新的应用版本,这既耗时又不灵活。不符合最佳实践:敏感信息应始终存储在安全、受控的环境中,例如后端服务器的数据库。

替代方案和最佳实践:

使用后端服务进行身份验证:这是最推荐的方式。客户端(Android应用)将用户输入的凭证发送到安全的后端服务器。服务器负责验证凭证(通常将用户密码的哈希值与数据库中存储的哈希值进行比较)。服务器返回一个会话令牌(如JWT),客户端使用该令牌进行后续的API请求。安全的通信:客户端与后端服务器之间的所有通信都应通过 HTTPS 进行加密,以防止中间人攻击。本地存储(仅用于非敏感或加密数据):如果需要在本地存储少量用户数据(如用户偏好设置),应使用 SharedPreferences,但绝不应存储明文密码。对于敏感数据,应进行加密处理。输入验证:除了检查用户名和密码是否匹配,还应该在客户端进行基本的输入验证,例如检查输入是否为空、是否符合特定格式(如邮箱格式)、长度限制等,以提供更好的用户体验并减轻服务器负担。用户体验:在网络请求或耗时操作期间,显示加载动画,避免UI卡顿。提供清晰、友好的错误提示信息。

5. 总结

本教程详细阐述了如何在Android应用中构建一个基本的登录表单,并重点纠正了在处理用户输入时常见的逻辑错误——过早地获取 EditText 内容。通过将 getText().toString() 调用移至按钮的 onClick 方法内部,我们确保了验证逻辑能够实时获取并处理用户的实际输入。

更重要的是,文章强调了在实际开发中遵循安全最佳实践的重要性。硬编码敏感信息(如用户名和密码)是极其危险的,应始终通过安全的后端服务进行身份验证,并确保客户端与服务器之间的通信经过加密。在实现功能的同时,将安全性置于首位,是构建健壮、可靠Android应用的关键。

以上就是Android登录验证教程:正确获取用户输入与安全实践的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1054595.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
尚界H5辅助驾驶七大场景测试全通关 配华为乾崑ADS 4
上一篇 2025年12月2日 04:49:54
css max-width与min-width在响应式设计中作用
下一篇 2025年12月2日 04:50:00

相关推荐

  • AI聊天助手有哪些_好用的AI聊天助手工具大全

    AI聊天助手有哪些_好用的AI聊天助手工具大全AI聊天助手有哪些_好用的AI聊天助手工具大全AI聊天助手有哪些_好用的AI聊天助手工具大全AI聊天助手有哪些_好用的AI聊天助手工具大全

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 豆包:字节跳动推出的免费AI智能助手 问小白:免费AI智能助手,支持DeepSeek满血版 讯飞星火:AI智能助手,支持PPT生成、深度推理 逗逗:AI游戏陪玩,支持原神、黑神话、LOL! 立即…

    2026年9月24日 • 用户投稿
    100
  • AIGC官网检测入口 知网免费查重直达链接

    知网AIGC检测与查重服务面向个人开放,官方入口为https://cx.cnki.net,按2元/千字符收费,提供简洁版与全文版报告,检测结果分四级标识AI生成风险,建议使用前确认学校要求并注意隐私保护。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 …

    2026年9月24日
    400
  • Java字符串处理:高效移除末尾逗号与空格的教程

    Java字符串处理:高效移除末尾逗号与空格的教程Java字符串处理:高效移除末尾逗号与空格的教程Java字符串处理:高效移除末尾逗号与空格的教程Java字符串处理:高效移除末尾逗号与空格的教程

    本教程将详细介绍如何在Java中高效、精确地移除字符串末尾的逗号、空格或其他指定分隔符。我们将探讨使用String.replaceAll()方法结合正则表达式的强大功能,以解决传统replace()方法无法精准定位末尾字符的问题,并提供多种场景下的示例代码与注意事项。 1. 引言:字符串清理的常见挑…

    2026年9月24日 • 用户投稿
    100
  • UC浏览器阅读模式怎么开启_UC浏览器网页小说阅读模式使用教程

    UC浏览器阅读模式怎么开启_UC浏览器网页小说阅读模式使用教程UC浏览器阅读模式怎么开启_UC浏览器网页小说阅读模式使用教程UC浏览器阅读模式怎么开启_UC浏览器网页小说阅读模式使用教程UC浏览器阅读模式怎么开启_UC浏览器网页小说阅读模式使用教程

    开启UC浏览器阅读模式可提升网页小说阅读体验,去除广告并优化排版。2. 可通过菜单按钮手动开启,或等待浏览器自动识别提示进入。3. 对未识别页面可用“readpage://”前缀强制启用阅读模式。 如果您在浏览网页小说时希望获得更清晰、无广告的阅读体验,可以通过开启UC浏览器的阅读模式来优化页面显示…

    2026年9月24日 • 用户投稿
    000
  • 抖音辅助账号上限怎么解除?抖音辅助账号上限解除最简单方法

    抖音辅助账号上限怎么解除?抖音辅助账号上限解除最简单方法抖音辅助账号上限怎么解除?抖音辅助账号上限解除最简单方法抖音辅助账号上限怎么解除?抖音辅助账号上限解除最简单方法抖音辅助账号上限怎么解除?抖音辅助账号上限解除最简单方法

    在如今火爆的短视频领域,抖音已成为众多内容创作者和商家运营的首选平台。为了实现更高效的推广与内容分发,不少人选择使用辅助账号来配合主账号运营。然而,“抖音辅助账号上限”这一问题常常让用户感到困扰。本文将为你全面解析抖音辅助账号上限怎么解除,并分享最实用、最简单的解决策略,助你轻松突破限制,玩转抖音生…

    2026年9月24日 • 用户投稿
    000
  • 下一代GPU的功耗会突破1000W吗?

    下一代GPU的功耗会突破1000W吗?下一代GPU的功耗会突破1000W吗?下一代GPU的功耗会突破1000W吗?下一代GPU的功耗会突破1000W吗?

    消费级GPU尚未突破1000W,RTX 5090约575W–600W;而数据中心AI芯片如英伟达B200已达1000W,GB200模块超1700W,进入“千瓦时代”。 下一代GPU的功耗是否会突破1000W,要分消费级和数据中心两个层面来看。目前来看,消费级显卡尚未达到这一水平,但数据中心级的AI芯…

    2026年9月24日 • 用户投稿
    200
  • sublime怎么设置markdown的图片预览_sublime Markdown图片预览设置

    sublime怎么设置markdown的图片预览_sublime Markdown图片预览设置sublime怎么设置markdown的图片预览_sublime Markdown图片预览设置sublime怎么设置markdown的图片预览_sublime Markdown图片预览设置sublime怎么设置markdown的图片预览_sublime Markdown图片预览设置

    Sublime Text需安装插件实现Markdown图片预览:1. 通过Package Control安装MarkdownEditing、MarkdownPreview或OmniMarkupPreviewer;2. 使用MarkdownPreview在浏览器中预览,确保图片路径正确;3. Omni…

    2026年9月24日 • 用户投稿
    100
  • 马斯克第六次起诉 OpenAI,指控窃取商业机密

    马斯克第六次起诉 OpenAI,指控窃取商业机密马斯克第六次起诉 OpenAI,指控窃取商业机密马斯克第六次起诉 OpenAI,指控窃取商业机密马斯克第六次起诉 OpenAI,指控窃取商业机密

    马斯克再度将 openai 告上法庭,这是他在过去十八个月内第六次针对这家人工智能公司发起法律行动。此次,由马斯克创立的人工智能企业 xai 已向加利福尼亚北区联邦法院提交诉状,指控 openai 大规模挖角其关键技术人才,并涉嫌非法获取商业机密。 随着双方矛盾不断升级,诉讼内容也从最初的合同纠纷逐…

    2026年9月24日 • 用户投稿
    000
  • 利用Laravel高效串联查询:从上一个结果获取数据

    本教程旨在解决laravel中基于前一个查询结果进行后续查询的常见问题。文章详细阐述了如何避免因`take(1)->toarray()`导致的多维数组问题,并优化了查询效率,通过使用`first()`方法获取单个记录,并直接在数据库层面进行过滤,而非在内存中处理大量数据,从而提升应用性能和代码…

    2026年9月24日
    600
  • VibeVoice— 微软推出的开源文本转语音模型

    VibeVoice— 微软推出的开源文本转语音模型VibeVoice— 微软推出的开源文本转语音模型VibeVoice— 微软推出的开源文本转语音模型VibeVoice— 微软推出的开源文本转语音模型

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 微软文字转语音 微软文本转语音,支持选择多种语音风格,可调节语速。 0 查看详情 VibeVoice是什么 vibevoice 是微软最新推出的文本到语音(tts)模型,能够生成具有丰富情感、支…

    2026年9月24日 • 用户投稿
    800
  • windows安全删除硬件图标不见了怎么办_安全删除硬件图标不见了的解决方法

    windows安全删除硬件图标不见了怎么办_安全删除硬件图标不见了的解决方法windows安全删除硬件图标不见了怎么办_安全删除硬件图标不见了的解决方法windows安全删除硬件图标不见了怎么办_安全删除硬件图标不见了的解决方法windows安全删除硬件图标不见了怎么办_安全删除硬件图标不见了的解决方法

    首先检查通知区域设置是否隐藏图标,依次通过调整任务栏显示、禁用USB暂停设置、重新启用USB根集线器、重建图标缓存及修复注册表路径HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionExplorerDriveIcons来恢复安全删除硬件图标…

    2026年9月24日 • 用户投稿
    100
  • 高德地图APP怎么添加地点_高德地图APP新增地点与收藏管理步骤

    高德地图APP怎么添加地点_高德地图APP新增地点与收藏管理步骤高德地图APP怎么添加地点_高德地图APP新增地点与收藏管理步骤高德地图APP怎么添加地点_高德地图APP新增地点与收藏管理步骤高德地图APP怎么添加地点_高德地图APP新增地点与收藏管理步骤

    可通过搜索、地图长按或定位当前地等方式在高德地图添加收藏,并创建分类收藏夹管理,具体操作包括输入关键词选地点收藏、长按地图标记红点添加、点击定位点保存位置,以及进入“我的”-“收藏夹”进行分组、重命名、移动、分享或批量删除等管理操作。 如果您想在高德地图中添加常去的地点或管理已有收藏,可以通过多种方…

    2026年9月24日 • 用户投稿
    200
  • AI 赋能硬件!荣耀宣布 Magic8 系列拥有“八大行业领先”

    AI 赋能硬件!荣耀宣布 Magic8 系列拥有“八大行业领先”AI 赋能硬件!荣耀宣布 Magic8 系列拥有“八大行业领先”AI 赋能硬件!荣耀宣布 Magic8 系列拥有“八大行业领先”AI 赋能硬件!荣耀宣布 Magic8 系列拥有“八大行业领先”

    10 月 15 日,荣耀即将正式推出 magic8 系列新机。在发布会前夕,官方持续释放预热信息。据 cnmo 获悉,最新一轮预热中,荣耀强调:magic8 系列配备品牌史上最强的硬件组合,通过 ai 深度赋能硬件系统,打造八大行业领先技术,树立新一代旗舰标杆。 荣耀 Magic8 系列 那么,这“…

    2026年9月24日 • 用户投稿
    100
  • 创建包含列表对象的Java对象时,避免列表为空的技巧

    创建包含列表对象的Java对象时,避免列表为空的技巧创建包含列表对象的Java对象时,避免列表为空的技巧创建包含列表对象的Java对象时,避免列表为空的技巧创建包含列表对象的Java对象时,避免列表为空的技巧

    在Java中,如果一个类的属性是列表类型,在创建该类的实例时,如果没有显式地初始化该列表,那么该属性的默认值将会是null。这可能会导致在后续操作中出现空指针异常。为了避免这种情况,我们需要确保在创建对象时,列表属性被初始化为一个空列表,而不是null。 解决方案一:显式初始化列表 最直接的方法是在…

    2026年9月24日 • 用户投稿
    100
  • 小红书原创声明怎么弄出来?小红书申请原创

    小红书原创声明怎么弄出来?小红书申请原创小红书原创声明怎么弄出来?小红书申请原创小红书原创声明怎么弄出来?小红书申请原创小红书原创声明怎么弄出来?小红书申请原创

    在内容为王的当下,小红书已成为用户分享生活点滴、表达观点和获取信息的重要阵地。原创内容的价值日益凸显,而如何在平台上有效声明并保护自己的原创成果,成为许多创作者关注的重点。接下来,就为大家全面解读小红书原创声明的操作方法。 一、什么是原创声明? 原创声明是作者对其创作内容拥有著作权的一种公开宣告,在…

    2026年9月24日 • 用户投稿
    000
  • UC浏览器下载的压缩包怎么打开_UC浏览器直接解压ZIP或RAR文件教程

    UC浏览器下载的压缩包怎么打开_UC浏览器直接解压ZIP或RAR文件教程UC浏览器下载的压缩包怎么打开_UC浏览器直接解压ZIP或RAR文件教程UC浏览器下载的压缩包怎么打开_UC浏览器直接解压ZIP或RAR文件教程UC浏览器下载的压缩包怎么打开_UC浏览器直接解压ZIP或RAR文件教程

    首先尝试用UC浏览器预览压缩包内容,若需完整解压则安装ZArchiver等工具,或使用系统文件管理器自带的ZIP解压功能。 如果您在使用UC浏览器下载了ZIP或RAR格式的压缩包,但无法直接查看其中的内容,可能是因为浏览器本身不支持完整的解压功能。此时需要借助系统自带或第三方工具完成解压操作。 本文…

    2026年9月24日 • 用户投稿
    200
  • 蚂蚁百灵大模型团队开源高性能思考模型 Ring-flash-2.0

    蚂蚁百灵大模型团队开源高性能思考模型 Ring-flash-2.0蚂蚁百灵大模型团队开源高性能思考模型 Ring-flash-2.0蚂蚁百灵大模型团队开源高性能思考模型 Ring-flash-2.0蚂蚁百灵大模型团队开源高性能思考模型 Ring-flash-2.0

    蚂蚁百灵大模型团队宣布正式开源 ring-flash-2.0,这是一款基于 ling-flash-2.0-base 深度优化的高效思考模型。与 ling-flash-2.0 一致,ring-flash-2.0 拥有总计 100b 参数,但在每次推理过程中仅激活 6.1b 参数,显著提升计算效率。 R…

    2026年9月24日 • 用户投稿
    000
  • 多模态AI如何处理射电望远镜数据 多模态AI深空探测应用

    多模态AI如何处理射电望远镜数据 多模态AI深空探测应用多模态AI如何处理射电望远镜数据 多模态AI深空探测应用多模态AI如何处理射电望远镜数据 多模态AI深空探测应用多模态AI如何处理射电望远镜数据 多模态AI深空探测应用

    多模态ai通过融合多种数据提升射电望远镜数据分析能力。它将无线电信号转化为频谱图、时间序列等形式,并结合光学图像等信息综合判断信号频率、强度、出现时间与方向;1.时空对齐匹配不同设备数据;2.特征级融合提取关键特征;3.决策级融合综合多个模型结果;实际应用于“突破聆听计划”筛选射电信号,面临数据格式…

    2026年9月24日 • 用户投稿
    200
  • sublime怎么处理SQL文件并高亮_sublime SQL语法高亮设置方法

    sublime怎么处理SQL文件并高亮_sublime SQL语法高亮设置方法sublime怎么处理SQL文件并高亮_sublime SQL语法高亮设置方法sublime怎么处理SQL文件并高亮_sublime SQL语法高亮设置方法sublime怎么处理SQL文件并高亮_sublime SQL语法高亮设置方法

    首先手动设置SQL语法高亮,点击右下角语言模式选择SQL;接着将.sql文件默认关联为SQL语法打开;然后通过Package Control安装SQLTools等插件增强功能;最后可自定义颜色主题优化显示效果。 Sublime Text 默认支持多种编程语言的语法高亮,但对 SQL 文件的支持可能不…

    2026年9月24日 • 用户投稿
    000
  • 如何在Java中实现继承

    Java中通过extends实现继承,子类可继承父类非私有成员并扩展功能;支持方法重写(@Override)和super调用父类成员或构造器,构造器需用super()初始化父类,且Java仅支持单继承,可通过接口弥补。 在Java中实现继承,主要通过extends关键字让一个类继承另一个类的属性和方…

    2026年9月24日
    300

发表回复

登录后才能评论
关注微信