电子公文传输系统安全-进展2
- 上周任务完成情况
完成对于登陆过程中的加盐操作:
SM3加盐算法存储密码的实现类
加盐思路: 1.通过UUID拿到盐值 2.拼接:盐值+明文密码 3.对2中数据进行SM3哈希 4.拼接: 盐值 + ”^“ + 3中的哈希值
明文密码走完上述流程后后存入数据库
登录验证: 1.根据用户名在数据库里得到对应的密文 2.根据密文密码获取该用户的盐值 3.将用户输入的登录密码走完上述加盐思路 4.与数据库密文密码进行对比
相关代码:
Sm3SaltUtil.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | package com.example.demo.util; import org.springframework.util.StringUtils; import java.util.UUID; import org.bouncycastle.crypto.digests.SM3Digest; public class Sm3SaltUtil { /** * 用户注册 * 调用该方法进行SM3加盐处理后存入数据库 * @param password * @return */ public static String encrypt(String password) { // 1.生成盐值 String salt = UUID.randomUUID().toString().replace( "-" , "" ); // 2.生成加盐后的SM3哈希值 String saltPassword = sm3Hash(salt + password); // 3.生成最终存入数据库的加密密码 65位固定规则 String finalPassword = salt + "^" + saltPassword; return finalPassword; } /** * 用户登录的工具方法 * 该方法是对用户输入的密码进行上述加盐操作后与数据库密文密码进行比较的工具方法 * @param password * @param salt * @return */ public static String encrypt(String password, String salt) { // 1.得到加盐之后的SM3哈希值 String saltPassword = sm3Hash(salt + password); // 2.生成最终密码 String finalPassword = salt + "^" + saltPassword; return finalPassword; } /** * 用户登录密码正确性验证 * @param password 用户登录时输入的密码 * @param dbFinalPassword 用户数据库里最终的加密密码 * @return */ public static boolean check(String password, String dbFinalPassword) { if (StringUtils.hasLength(password) && StringUtils.hasLength(dbFinalPassword) && dbFinalPassword.length() == 97 ) { String salt = dbFinalPassword.split( "\\^" )[ 0 ]; String confirmFinalPassword = encrypt(password, salt); if (dbFinalPassword.equals(confirmFinalPassword)) { return true ; } } return false ; } /** * 使用SM3算法进行哈希计算 * @param input 输入字符串 * @return 哈希结果的十六进制表示 */ private static String sm3Hash(String input) { SM3Digest digest = new SM3Digest(); byte [] data = input.getBytes(); digest.update(data, 0 , data.length); byte [] hash = new byte [digest.getDigestSize()]; digest.doFinal(hash, 0 ); return bytesToHex(hash); } /** * 将字节数组转换为十六进制字符串表示 * @param bytes 字节数组 * @return 十六进制字符串 */ private static String bytesToHex( byte [] bytes) { StringBuilder sb = new StringBuilder(); for ( byte b : bytes) { String hex = Integer.toHexString(b & 0xFF ); if (hex.length() == 1 ) { sb.append( '0' ); } sb.append(hex); } return sb.toString(); } } |
login:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | package com.example.demo.controller; import com.example.demo.component.GeneratorId; import com.example.demo.component.TokenUtil; import com.example.demo.enums.Code; import com.example.demo.enums.Keys; import com.example.demo.pojo.entity.UserInfo; import com.example.demo.service.UserInfoService; import com.example.demo.util.Sm3SaltUtil; import com.example.demo.util.Return; import org.apache.ibatis.annotations.Param; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.UUID; import java.util.concurrent.TimeUnit; @Controller @ResponseBody @RequestMapping ( "/public/user" ) public class UserInfoController { @Autowired private UserInfoService userInfoService; @Autowired private TokenUtil tokenUtil; @Autowired private GeneratorId generatorId; @GetMapping ( "/login" ) public Return userLogin(UserInfo user, HttpServletRequest request) { if (user == null || !StringUtils.hasLength(user.getAccount()) || !StringUtils.hasLength(user.getPassword())) { // 非法参数 return Return.fail(Code.FAIL_NORMAL); } // 处理登录请求:查询数据库密码通过Sm3封装的方法进行对比 // 1.查询数据库 UserInfo dbUser = userInfoService.login(user); if (dbUser == null || dbUser.getId() <= 0 ) { return Return.fail(Code.FAIL_LOGIN); } // 2.调用Sm3工具类方法进行对比 if (!Sm3SaltUtil.check(user.getPassword(),dbUser.getPassword())) { // 密码不一样,登录失败 return Return.fail(Code.FAIL_LOGIN); } // 3.登录成功,可存入redis key-token:生成的随机唯一值 value:user String ip = request.getRemoteAddr(); dbUser.setPassword( "******" ); dbUser.setIp(ip); //TokenUtil.setObjectInSession(ApplicationVariable.USER_SESSION_KRY,dbUser,request); // 3.redis实现token // 3.1 生成随机token String token = UUID.randomUUID().toString().replace( "-" , "" ); // 3.2 保存到redis tokenUtil.setUserInfo(token,dbUser,30L, TimeUnit.MINUTES); // 5.返回登录成功 返回token 后续携带token return Return.success(Code.SUCCESS_NORMAL,token); } @PostMapping ( "/enroll" ) public Return enroll(UserInfo user, HttpServletRequest request) { // 非法校验 if (user == null || !StringUtils.hasLength(user.getAccount()) || !StringUtils.hasLength(user.getPassword())) { return Return.fail(Code.FAIL_NORMAL); } // 调用Sm3工具类进行密码加密 String password = user.getPassword(); password = Sm3SaltUtil.encrypt(password); user.setPassword(password); // 获取ip String ip = request.getRemoteAddr(); user.setIp(ip); // 生成id user.setId(generatorId.nextId(Keys.USER_ID.getKey())); // 注册 int result = userInfoService.enroll(user); if (result != 1 ) { // 注册失败 return Return.fail(Code.FAIL_NORMAL); } // 返回 return Return.success(Code.SUCCESS_NORMAL); } @GetMapping ( "/logout" ) public Return logout( @RequestHeader ( "token" )String token) { // 删除token tokenUtil.removeUserInfo(Keys.USER_TOKEN + token); return Return.success(Code.SUCCESS_NORMAL); } @RequestMapping ( "/list" ) public Return list( @RequestHeader ( "token" ) String token) { // 1. 查看权限 UserInfo user = tokenUtil.getUserInfo(token); if (user == null || user.getId() == 1 ) { return Return.fail(Code.NOT_SEE); } // 2. 返回 return Return.success(Code.SUCCESS_NORMAL, userInfoService.list()); } @RequestMapping ( "/count" ) public Return count() { return Return.success(Code.SUCCESS_NORMAL,userInfoService.count()); } @GetMapping ( "/info" ) public Return info( @RequestHeader ( "token" )String token) { if (token == null ) { return Return.fail(Code.FAIL_NORMAL); } UserInfo userInfo = tokenUtil.getUserInfo(token); if (userInfo == null ) { return Return.fail(Code.FAIL_NORMAL); } UserInfo userInfoVo = new UserInfo(); userInfoVo.setAccount(userInfo.getAccount()); userInfoVo.setStatus(userInfo.getStatus()); return Return.success(Code.SUCCESS_NORMAL,userInfoVo); } } |
实验预期:
- 本周计划
完成审计的相关设计
实验代码:
实验预期:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!