020-从零搭建微服务-认证中心(九)

写在最前

如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。

源码地址(后端):https://gitee.com/csps/mingyue

源码地址(前端):https://gitee.com/csps/mingyue-ui

文档地址:https://gitee.com/csps/mingyue/wikis

密码加密

密码加密是安全认证不可或缺的部分, Sa-Token在 v1.14 版本添加密码加密模块,该模块非常简单,仅仅封装了一些常见的加密算法。

本系统将采用 BCrypt加密 加密方式对密码加密!!!

摘要加密

md5、sha1、sha256

java 复制代码
// md5加密 
SaSecureUtil.md5("123456");

// sha1加密 
SaSecureUtil.sha1("123456");

// sha256加密 
SaSecureUtil.sha256("123456");

对称加密

AES加密

java 复制代码
// 定义秘钥和明文
String key = "123456";
String text = "Sa-Token 一个轻量级java权限认证框架";

// 加密 
String ciphertext = SaSecureUtil.aesEncrypt(key, text);
System.out.println("AES加密后:" + ciphertext);

// 解密 
String text2 = SaSecureUtil.aesDecrypt(key, ciphertext);
System.out.println("AES解密后:" + text2);

非对称加密

RSA加密

java 复制代码
// 定义私钥和公钥 
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAO+wmt01pwm9lHMdq7A8gkEigk0XKMfjv+4IjAFhWCSiTeP7dtlnceFJbkWxvbc7Qo3fCOpwmfcskwUc3VSgyiJkNJDs9ivPbvlt8IU2bZ+PBDxYxSCJFrgouVOpAr8ar/b6gNuYTi1vt3FkGtSjACFb002/68RKUTye8/tdcVilAgMBAAECgYA1COmrSqTUJeuD8Su9ChZ0HROhxR8T45PjMmbwIz7ilDsR1+E7R4VOKPZKW4Kz2VvnklMhtJqMs4MwXWunvxAaUFzQTTg2Fu/WU8Y9ha14OaWZABfChMZlpkmpJW9arKmI22ZuxCEsFGxghTiJQ3tK8npj5IZq5vk+6mFHQ6aJAQJBAPghz91Dpuj+0bOUfOUmzi22obWCBncAD/0CqCLnJlpfOoa9bOcXSusGuSPuKy5KiGyblHMgKI6bq7gcM2DWrGUCQQD3SkOcmia2s/6i7DUEzMKaB0bkkX4Ela/xrfV+A3GzTPv9bIBamu0VIHznuiZbeNeyw7sVo4/GTItq/zn2QJdBAkEA8xHsVoyXTVeShaDIWJKTFyT5dJ1TR++/udKIcuiNIap34tZdgGPI+EM1yoTduBM7YWlnGwA9urW0mj7F9e9WIQJAFjxqSfmeg40512KP/ed/lCQVXtYqU7U2BfBTg8pBfhLtEcOg4wTNTroGITwe2NjL5HovJ2n2sqkNXEio6Ji0QQJAFLW1Kt80qypMqot+mHhS+0KfdOpaKeMWMSR4Ij5VfE63WzETEeWAMQESxzhavN1WOTb3/p6icgcVbgPQBaWhGg==";
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvsJrdNacJvZRzHauwPIJBIoJNFyjH47/uCIwBYVgkok3j+3bZZ3HhSW5Fsb23O0KN3wjqcJn3LJMFHN1UoMoiZDSQ7PYrz275bfCFNm2fjwQ8WMUgiRa4KLlTqQK/Gq/2+oDbmE4tb7dxZBrUowAhW9NNv+vESlE8nvP7XXFYpQIDAQAB";

// 文本
String text = "Sa-Token 一个轻量级java权限认证框架";

// 使用公钥加密
String ciphertext = SaSecureUtil.rsaEncryptByPublic(publicKey, text);
System.out.println("公钥加密后:" + ciphertext);

// 使用私钥解密
String text2 = SaSecureUtil.rsaDecryptByPrivate(privateKey, ciphertext);
System.out.println("私钥解密后:" + text2); 

私钥和公钥调用以下方法生成即可

java 复制代码
// 生成一对公钥和私钥,其中Map对象 (private=私钥, public=公钥)
System.out.println(SaSecureUtil.rsaGenerateKeyPair());

Base64编码与解码

java 复制代码
// 文本
String text = "Sa-Token 一个轻量级java权限认证框架";

// 使用Base64编码
String base64Text = SaBase64Util.encode(text);
System.out.println("Base64编码后:" + base64Text);

// 使用Base64解码
String text2 = SaBase64Util.decode(base64Text);
System.out.println("Base64解码后:" + text2); 

BCrypt加密

由它加密的文件可在所有支持的操作系统和处理器上进行转移

java 复制代码
// 使用方法
String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt()); 

// 使用checkpw方法检查被加密的字符串是否与原始字符串匹配:
BCrypt.checkpw(candidate_password, stored_hash); 

// gensalt方法提供了可选参数 (log_rounds) 来定义加盐多少,也决定了加密的复杂度:
String strong_salt = BCrypt.gensalt(10);
String stronger_salt = BCrypt.gensalt(12); 

密文登录

1. 明文密码生成密文

java 复制代码
// 生成加密盐
String gensalt = BCrypt.gensalt();

String pw_hash = BCrypt.hashpw("123456", gensalt); 

// 打印加密后的密文
System.out.println(pw_hash);
// $2a$12$pBVti6NTcVJxptxHNqetBewxqwJU54.sItx3b8U2Kl44XnQinfUHq

2. 生成加密盐放入 Nacos

mingyue-auth.yml

yaml 复制代码
# 用户配置
user:
  password:
    # 私钥
    salt: $2a$12$pBVti6NTcVJxptxHNqetBe

用户密码配置类

java 复制代码
@Data
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "user.password")
public class UserPasswordProperties {

	/**
	 * 密码加盐
	 */
	private String salt;

}

3. 修改数据库用户密码

sql 复制代码
INSERT INTO `sys_user` VALUES (1, 'mingyue', '明月', '0', '$2a$12$pBVti6NTcVJxptxHNqetBewxqwJU54.sItx3b8U2Kl44XnQinfUHq', '13288888888', NULL, NULL, '0', '0', '2023-07-19 17:06:22', '2023-07-19 17:06:25', 'mingyue', 'mingyue');
INSERT INTO `sys_user` VALUES (2, 'strive', 'Strive', '0', '$2a$12$pBVti6NTcVJxptxHNqetBewxqwJU54.sItx3b8U2Kl44XnQinfUHq', '15388888888', NULL, NULL, '0', '0', '2023-07-19 17:06:22', '2023-07-19 17:06:25', 'mingyue', 'mingyue');

4. 修改登录密码校验

java 复制代码
public SaTokenInfo login(PasswordLoginDto dto) {
		// 远程调用用户服务
		R<LoginUser> userInfoResp = remoteUserService.userInfo(dto.getUsername());

		if (Objects.isNull(userInfoResp) || Objects.isNull(userInfoResp.getData())) {
			return null;
		}

		LoginUser userInfo = userInfoResp.getData();

    // 登录密码校验
		if (!userInfo.getPassword().equals(dto.getPassword())) {
			throw new UserException("密码错误,请重试!");
		}

		if (dto.getUsername().equals(userInfo.getUsername()) && dto.getPassword().equals(userInfo.getPassword())) {
			// 第1步,先登录上
			LoginHelper.login(userInfo);
			// 第2步,获取 Token 相关参数
			SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

			return tokenInfo;
		}

		return null;
	}

5.启动测试

5.1. 明文测试

bash 复制代码
curl -X 'POST' \
  'http://mingyue-gateway:9100/auth/login' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "username": "mingyue",
  "password": "123456"
}'

测试结果

json 复制代码
{
  "code": 500,
  "msg": "密码错误,请重试!",
  "data": null
}

5.2. 密文测试

bash 复制代码
curl -X 'POST' \
  'http://mingyue-gateway:9100/auth/login' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "username": "mingyue",
  "password": "$2a$12$pBVti6NTcVJxptxHNqetBewxqwJU54.sItx3b8U2Kl44XnQinfUHq"
}'

测试结果

json 复制代码
{
  "code": 200,
  "msg": "登录成功",
  "data": "nHefN9Z9t3bptgQ5CI3nMMqPuCEOS03n"
}

MingYue-UI登录修改

明文转密文

state.ruleForm.password = bcryptjs.hashSync(state.ruleForm.password, state.salt);

js 复制代码
const onSignIn = async () => {
	state.loading.signIn = true;
  state.ruleForm.password = bcryptjs.hashSync(state.ruleForm.password, state.salt);
	useLoginApi().signIn(state.ruleForm).then(async res => {
		// 存储 token 到浏览器缓存
		Session.set('token', res.data);
		// 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.ts` 中不同用户登录判断(模拟数据)
		Cookies.set('username', state.ruleForm.username);
		if (!themeConfig.value.isRequestRoutes) {
			// 前端控制路由,2、请注意执行顺序
			const isNoPower = await initFrontEndControlRoutes();
			signInSuccess(isNoPower);
		} else {
			// 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
			// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
			const isNoPower = await initBackEndControlRoutes();
			// 执行完 initBackEndControlRoutes,再执行 signInSuccess
			signInSuccess(isNoPower);
		}
	});

};

小结

现在终于不是明文登录啦~

目前 mingyue-ui 的登录验证码还是固定的,接下来,我们需要把验证码用上,冲!

相关推荐
mghio2 小时前
Dubbo 中的集群容错
java·微服务·dubbo
uhakadotcom4 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
沉登c7 小时前
第 3 章 事务处理
架构
阿里云云原生7 小时前
LLM 不断提升智能下限,MCP 不断提升创意上限
云原生
阿里云云原生7 小时前
GraalVM 24 正式发布阿里巴巴贡献重要特性 —— 支持 Java Agent 插桩
云原生
数据智能老司机10 小时前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构
数据智能老司机10 小时前
CockroachDB权威指南——开始使用
数据库·分布式·架构
云上艺旅10 小时前
K8S学习之基础七十四:部署在线书店bookinfo
学习·云原生·容器·kubernetes
c无序10 小时前
【Docker-7】Docker是什么+Docker版本+Docker架构+Docker生态
docker·容器·架构
数据智能老司机11 小时前
CockroachDB权威指南——CockroachDB 架构
数据库·分布式·架构