福州市做公司网站哪家好,用jsp做网站的难点,网站优化案例,网站数据库访问1.问题
账密登录方式中用户输入密码后#xff0c;把账号、密码通过http传输到后端进行校验#xff0c;然而密码属于敏感信息#xff0c;不能以明文传输#xff0c;否则容易被拦截窃取#xff0c;因此需要考虑如何安全传输密码
2.解决方案
使用rsa加密方式#xff0c;r…1.问题
账密登录方式中用户输入密码后把账号、密码通过http传输到后端进行校验然而密码属于敏感信息不能以明文传输否则容易被拦截窃取因此需要考虑如何安全传输密码
2.解决方案
使用rsa加密方式rsa属于非对称加密特点就是公钥加密私钥解密
2.1后端生成公钥私钥
生成公私钥把公钥返回给前端私钥用redis缓存
ManagerController.java GetMapping(/key)public ResponseEntityApiResponse key(RequestParam(loginNo) String loginNo) {String key managerService.generateKey(loginNo);return ApiResponse.success(key);}ManagerServiceImpl.java Overridepublic String generateKey(String loginNo) {QueryWrapperManager wrapper new QueryWrapper();wrapper.eq(loginNo, loginNo);Manager entity this.getOne(wrapper);if (Objects.isNull(entity)) {throw new CodeException(用户不存在loginNo loginNo);}try {KeyPair keyPair RSAUtil.generateKeyPair();String publicKey RSAUtil.getPublicKey(keyPair);String privateKey RSAUtil.getPrivateKey(keyPair);log.info(publicKey{}, publicKey);log.info(privateKey{}, privateKey);String redisKey RedisKey.MANAGE_LOGIN_RSA_PRIVATEKEY $ loginNo;// 清除缓存redisService.del(redisKey);// 私钥添加到缓存redisService.set(redisKey, privateKey, 5, TimeUnit.MINUTES);return publicKey;} catch (Exception e) {log.error(生成rsa密钥失败, e);}return null;}RSAUtil.java
public class RSAUtil {private static final Charset CHARSET StandardCharsets.UTF_8;private static final String ALGORITHM RSA;/*** 生成密钥对* return* throws NoSuchAlgorithmException*/public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {KeyPairGenerator keyPairGenerator KeyPairGenerator.getInstance(ALGORITHM);keyPairGenerator.initialize(1024);return keyPairGenerator.generateKeyPair();}/*** 生成公钥* param keyPair* return*/public static String getPublicKey(KeyPair keyPair) {PublicKey publicKey keyPair.getPublic();byte[] bytes base64Encode(publicKey.getEncoded());return new String(bytes, CHARSET);}/*** 生成私钥* param keyPair* return*/public static String getPrivateKey(KeyPair keyPair) {PrivateKey privateKey keyPair.getPrivate();byte[] bytes base64Encode(privateKey.getEncoded());return new String(bytes, CHARSET);}/*** base64加密* param bytes* return*/public static byte[] base64Encode(byte[] bytes) {return Base64.getEncoder().encode(bytes);}/*** base64解密* param bytes* return*/public static byte[] base64Decode(byte[] bytes) {return Base64.getDecoder().decode(bytes);}/*** base64解密* param src* return*/public static byte[] base64Decode(String src) {return Base64.getDecoder().decode(src);}/*** 解密* param key* param data* return* throws NoSuchAlgorithmException* throws InvalidKeySpecException* throws NoSuchPaddingException* throws InvalidKeyException* throws IllegalBlockSizeException* throws BadPaddingException*/public static String decrypt(String key, String data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {byte[] bytes base64Decode(key);PKCS8EncodedKeySpec pkcs8EncodedKeySpec new PKCS8EncodedKeySpec(bytes);KeyFactory keyFactory KeyFactory.getInstance(ALGORITHM);PrivateKey privateKey keyFactory.generatePrivate(pkcs8EncodedKeySpec);Cipher cipher Cipher.getInstance(RSA/ECB/PKCS1Padding);cipher.init(Cipher.DECRYPT_MODE, privateKey);return new String(cipher.doFinal(base64Decode(data.getBytes(CHARSET))), CHARSET);}2.2前端使用公钥加密
安装这个依赖
npm install jsencrypt3.2.0import JSEncrypt from jsencrypt;// key为后端返回的公钥this.form.password为明文密码
const jsEncrypt new JSEncrypt();
jsEncrypt.setPublicKey(key);
// pwd为加密后的密码
var pwd jsEncrypt.encrypt(this.form.password);2.3后端使用私钥解密
从redis获取私钥用私钥解密得到明文后和数据库保存的密码比对数据库的密码是以用户id为盐值对明文密码作md5加密相同则放行否则报错注意登录成功的话需要把redis的密钥移除
ManagerController.java PostMapping(/login)public ResponseEntityApiResponse login(RequestParam(loginNo) String loginNo, RequestParam(password) String password)throws Exception {UserDTOWithToken dto managerService.login(loginNo, password);return ApiResponse.success(dto);}ManagerServiceImpl.java Overridepublic UserDTOWithToken login(String loginNo, String password) throws Exception {QueryWrapperManager wrapper new QueryWrapper();wrapper.eq(loginNo, loginNo);Manager entity this.getOne(wrapper);if (Objects.isNull(entity)) {throw new CodeException(用户不存在loginNo loginNo);}String redisKey RedisKey.MANAGE_LOGIN_RSA_PRIVATEKEY $ loginNo;// 从缓存获取私钥String privateKey (String) redisService.get(redisKey);if (StrUtil.isEmpty(privateKey)) {throw new CodeException(私钥不存在);}// 用私钥解密String realPassword RSAUtil.decrypt(privateKey, password);log.info(realPassword{}, realPassword);// 校验密码Digester digester new Digester(DigestAlgorithm.MD5);digester.setSalt(entity.getId().getBytes(StandardCharsets.UTF_8));String encodePassword digester.digestHex(realPassword);log.info(encodePassword{}, encodePassword);if (!encodePassword.equals(entity.getPassword())) {throw new CodeException(密码错误);}//从认证服务获取tokenResponseEntityApiResponse responseEntity authClient.token(AuthConst.PASSWORD_GRANT_TYPE, AuthConst.ADMIN_CLIENT_ID,AuthConst.ADMIN_CLIENT_SECRET, null, loginNo, password);ApiResponse response responseEntity.getBody();TokenDTO tokenDTO response.toObject(TokenDTO.class);if (Objects.isNull(tokenDTO)) {throw new CodeException(获取token失败 response.getMessage());}UserDTOWithToken dto new UserDTOWithToken();dto.setUserId(entity.getId());dto.setToken(tokenDTO);entity.setLoginTime(LocalDateTime.now());Integer loginCount entity.getLoginCount();entity.setLoginCount(Objects.isNull(loginCount) ? 1 : loginCount 1);entity.setUpdateTime(LocalDateTime.now());this.updateById(entity);// 成功则清除缓存的私钥redisService.del(redisKey);return dto;}3.总结
非对称加密还有其它算法rsa是其中一种
后端存储私钥除了redis也可以用其它缓存工具如J2Cache