-
封装与访问修饰符——用C#开发用户隐私信息保护
第一部分:C#基础入门
实例4:封装与访问修饰符——用户隐私信息保护
实例介绍
在软件系统中,用户隐私信息(如身份证号、密码、手机号)是核心敏感数据,封装和访问修饰符是保护这些数vb.net教程C#教程python教程SQL教程access 2010教程据的关键手段。封装通过“信息隐藏”原则,将敏感字段设为私有,仅暴露安全的访问接口;访问修饰符则控制字段/方法的可见范围,防止非法修改。本实例通过实现一个安全的用户类,带你掌握如何用封装保护隐私,理解不同访问修饰符的作用,写出安全、合规的代码。
需求分析
1.定义用户类:包含公开信息(姓名、年龄)和隐私信息(身份证号、密码);
2.隐私保护:
1.身份证号:禁止直接访问,仅允许脱敏显示(如110101****1234);
2.密码:加密存储(模拟MD5加密),禁止明文访问,修改需验证旧密码;
3.访问控制:
1.公开信息(姓名、年龄)可读写;
2.隐私信息仅通过指定方法访问/修改(如GetMaskedIdCard()、ChangePassword());
4.数据完整性:身份证号初始化时验证格式(模拟18位校验),密码长度不低于6位;
5.操作日志:记录隐私信息的修改操作(如密码修改时间)。
代码实现
csharp
using System;
using System.Security.Cryptography;
using System.Text;
namespace PrivacyProtectionDemo
{
// 用户类:封装隐私信息,控制访问权限
public class User
{
// 1. 私有字段:隐私信息(仅类内部可访问)
private string _idCard; // 身份证号(私有,禁止外部直接访问)
private string _encryptedPwd; // 加密后的密码(私有)
private DateTime _pwdLastChangedTime; // 密码最后修改时间(私有)
// 2. 公共属性:公开信息(外部可读写/只读)
public string Name { get; set; } // 姓名:可读写
public int Age { get; set; } // 年龄:可读写
public string Email { get; } // 邮箱:只读(构造函数初始化)
// 3. 构造函数:初始化用户信息,验证敏感数据格式
public User(string name, int age, string email, string idCard, string initialPwd)
{
Name = name;
Age = age;
Email = email; // 只读属性,仅构造函数可赋值
// 验证身份证格式(模拟18位校验)
if (!IsValidIdCard(idCard))
throw new ArgumentException("身份证号格式无效(需18位)");
_idCard = idCard;
// 验证初始密码长度,加密存储
if (initialPwd.Length < 6)
throw new ArgumentException("密码长度需≥6位");
_encryptedPwd = EncryptPassword(initialPwd);
_pwdLastChangedTime = DateTime.Now;
}
// 4. 公共方法:安全访问隐私信息(脱敏/加密)
/// <summary>
/// 获取脱敏身份证号(前6后4,中间隐藏)
/// </summary>
public string GetMaskedIdCard()
{
if (string.IsNullOrEmpty(_idCard)) return string.Empty;
return $"{_idCard.Substring(0,6)}******{_idCard.Substring(14)}";
}
/// <summary>
/// 修改密码(需验证旧密码)
/// </summary>
public bool ChangePassword(string oldPwd, string newPwd)
{
// 验证旧密码是否正确
if (EncryptPassword(oldPwd) != _encryptedPwd)
return false;
// 验证新密码长度
if (newPwd.Length <6)
return false;
// 更新加密密码和修改时间
_encryptedPwd = EncryptPassword(newPwd);
_pwdLastChangedTime = DateTime.Now;
return true;
}
/// <summary>
/// 获取密码最后修改时间(只读)
/// </summary>
public DateTime GetPwdLastChangedTime() => _pwdLastChangedTime;
// 5. 私有方法:内部工具(外部不可见)
/// <summary>
/// 模拟密码加密(实际项目用SHA256+盐)
/// </summary>
private string EncryptPassword(string pwd)
{
using (var md5 = MD5.Create())
{
byte[] bytes = Encoding.UTF8.GetBytes(pwd);
byte[] hash = md5.ComputeHash(bytes);
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
}
/// <summary>
/// 模拟身份证格式验证(仅检查长度)
/// </summary>
private bool IsValidIdCard(string idCard)
{
return !string.IsNullOrEmpty(idCard) && idCard.Length ==18;
}
}
// 主程序:测试用户隐私保护功能
class Program
{
static void Main(string[] args)
{
try
{
// 创建用户(初始化时验证身份证和密码)
var user = new User(
name: "张三",
age: 30,
email: "zhangsan@example.com",
idCard: "110101199405201234",
initialPwd: "Zhang123!"
);
// 访问公开信息
Console.WriteLine($"姓名:{user.Name}");
Console.WriteLine($"年龄:{user.Age}");
Console.WriteLine($"邮箱:{user.Email}"); // 只读属性,无法修改
// 访问隐私信息(脱敏显示)
Console.WriteLine($"脱敏身份证:{user.GetMaskedIdCard()}");
Console.WriteLine($"密码最后修改时间:{user.GetPwdLastChangedTime():yyyy-MM-dd HH:mm}");
// 尝试修改密码(正确旧密码)
bool pwdChanged = user.ChangePassword(oldPwd: "Zhang123!", newPwd: "NewPass456!");
Console.WriteLine($"密码修改成功?{pwdChanged}");
Console.WriteLine($"新密码修改时间:{user.GetPwdLastChangedTime():yyyy-MM-dd HH:mm}");
// 尝试直接访问私有字段(编译错误!)
// Console.WriteLine(user._idCard); // 错误:_idCard是private
// user._encryptedPwd = "123"; // 错误:_encryptedPwd是private
}
catch (Exception ex)
{
Console.WriteLine($"错误:{ex.Message}");
}
}
}
}
逐行讲解
-
访问修饰符的使用
private string _idCard:身份证号设为私有,仅User类内部可访问。外部代码无法直接读取/修改,避免隐私泄露;
public string Name { get; set; }:姓名设为公共可读写,属于公开信息,允许外部修改;
public string Email { get; }:邮箱设为公共只读,仅构造函数可初始化,外部无法修改,保证邮箱唯一性;
private string EncryptPassword(string pwd):加密方法设为私有,外部无需知道加密细节,仅内部使用。 -
隐私信息保护逻辑
身份证脱敏:GetMaskedIdCard()方法返回脱敏后的身份证号,隐藏中间敏感部分,既满足显示需求又保护隐私;
密码加密存储:EncryptPassword()方法用MD5模拟加密(实际项目需加盐+SHA256),禁止明文存储,即使数据泄露也无法直接获取密码;
密码修改验证:ChangePassword()方法需验证旧密码,防止非法修改,同时记录修改时间,便于审计。 -
数据完整性验证
构造函数验证:初始化用户时,验证身份证长度(模拟18位)和密码长度(≥6位),确保数据合法;
只读属性:Email设为只读,避免外部随意修改,保证用户身份唯一。
基础知识拓展 -
C#访问修饰符全解析
| 修饰符 | 作用范围 | 适用场景 |
| ---- | ---- | ---- |
| private | 仅当前类内部 | 隐私字段/内部工具方法(如加密、验证) |
| protected | 当前类+子类 | 需被子类继承的方法/字段(如User子类可访问的基础信息) |
| internal | 同一程序集(项目) | 程序集内部共享的类/方法(如工具类) |
| protected internal | 同一程序集+子类(跨程序集) | 需被子类继承且程序集内部共享的成员 |
| public | 全局可见 | 公开接口/公共类(如User类的公开方法) |
核心原则:最小权限原则——给成员分配尽可能小的访问范围,仅暴露必要的接口。
2. 封装的三大原则
信息隐藏:隐藏内部实现细节(如加密算法、验证逻辑),仅暴露抽象接口;
数据完整性:通过方法/属性控制数据修改,防止非法值(如密码长度不足);
模块化:将相关数据和方法封装到类中,提高代码可维护性。
3. 隐私保护进阶技巧
加盐加密:在密码前/后添加随机字符串(盐)再加密,防止彩虹表攻击;
敏感数据序列化忽略:用[JsonIgnore](Newtonsoft.Json)或[IgnoreDataMember]标记隐私字段,避免序列化泄露;
只读属性:用public string Prop { get; }实现只读字段,仅构造函数可赋值。
扩展思考
1.加强身份证验证:实现真实的18位身份证校验(如校验码计算),而非仅检查长度;
2.多因素认证:修改密码时添加短信验证码,进一步提升安全性;
3.敏感数据日志脱敏:记录操作日志时,自动脱敏身份证、手机号等敏感信息;
4.子类继承:创建AdminUser子类继承User,用protected修饰符让子类访问部分隐私信息(如简化密码修改流程);
5.数据过期策略:添加密码过期时间,强制用户定期修改密码。
总结
封装是保护用户隐私的核心手段,而访问修饰符是实现封装的“工具”。通过合理使用private隐藏敏感数据,public暴露必要接口,protected支持子类继承,我们能写出既安全又易维护的代码。记住:隐私保护不是可选功能,而是软件的基本责任——每一个敏感字段都应该被妥善封装,每一次数据访问都应该被严格控制。
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49405.html










