实战密码加密及全局异常处理

一、结果集返回帮助类

package com.lj.miaoskll.response;
 
import java.io.Serializable;
 
@SuppressWarnings("all")
public enum ResponseResultCode implements Serializable {
 
    /* 正常状态 */
    SUCCESS(200, "成功"),
    FAILURE(300, "失败"),
    UNKNOWN(400, "未知错误"),
    /**
     * 用户code范围: 1000;
     */
    USER_ACCOUNT_NOT_FIND(1001, "用户名不存在"),
    USER_ACCOUNT_DISABLED(1002, "该用户已被禁用"),
    USER_PASSWORD_NOT_MATCH(1003, "该用户密码不一致"),
    USER_PERMISSION_ERROR(1004, "该用户不具备访问权限"),
    USER_STATE_OFF_LINE(1005, "该用户未登录"),
    USER_CREDENTIAL_NOT_BE_EMPTY(1006, "用户的登录信息不能为空值"),
    USER_ACCOUNT_NOT_MOBLIE(1007, "该用户登录信息格式不符合"),
    USER_LOGIN_ERROR(1008, "登录失败"),
    /**
     * 其它异常: 4000;
     */
    TRIKET_ERROR(4001, "triket失效,请重新登录"),
    /**
     * 商品异常: 6000;
     */
    GOODS_ADD_ERROR(6001, "商品添加失败"),
    GOODS_EDIT_ERROR(6002, "商品修改失败"),
    GOODS_REMOVE_ERROR(6003, "商品删除失败");
 
    /*响应状态码*/
    private final Integer code;
    /*响应状态信息*/
    private final String message;
 
    /*此构造无法调用,用来定义常量枚举使用*/
    ResponseResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
 
    /**
     * 此方法用于配合{@link JsonResponseParse}实现快速返回json类型响应码
     * 需要结合{@link JsonResponseResult}注解使用
     *
     * @param code 响应码(对应枚举中的code,如无法找到则返回`UNKNOWN`)
     */
    public static ResponseResultCode queryCode(Integer code) {
        for (ResponseResultCode value : values()) {
            if (code.equals(value.code)) {
                return value;
            }
        }
        return UNKNOWN;
    }
 
    public Integer getCode() {
        return code;
    }
 
    public String getMessage() {
        return message;
    }
 
}
package com.lj.miaoskll.response;
 
import io.swagger.annotations.ApiModel;
import lombok.Data;
 
import java.io.Serializable;
 
@Data
@SuppressWarnings("all")
@ApiModel("返回数据类型")
public class ResponseResult<T> implements Serializable {
 
    private Integer code;
    private String message;
    private T data;
    private Long total;
 
    /**
     * 私有构造, 只允许通过static调用构造
     *
     * @param resultCode 结果枚举
     * @param data       响应数据
     */
    private ResponseResult(ResponseResultCode resultCode, T data) {
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
        this.data = data;
    }
 
    /**
     * 私有构造, 只允许通过static调用构造
     *
     * @param resultCode 结果枚举
     * @param data       响应数据
     * @param total      数据总大小(用于分页请求)
     */
    private ResponseResult(ResponseResultCode resultCode, Long total, T data) {
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
        this.data = data;
        this.total = total;
    }
 
    /**
     * 成功调用返回的结果(无数据携带)
     */
    public static ResponseResult<?> success() {
        return success(null);
    }
 
    /**
     * 成功调用返回的结果(数据携带)
     *
     * @param data 携带的数据
     */
    public static <T> ResponseResult success(T data) {
        return new ResponseResult(ResponseResultCode.SUCCESS, data);
    }
 
    /**
     * 成功调用返回的结果(分页使用)
     *
     * @param data  携带的数据
     * @param total 数据总条数
     */
    public static <T> ResponseResult success(T data, Long total) {
        return new ResponseResult(ResponseResultCode.SUCCESS, total, data);
    }
 
    /**
     * 失败调用返回的结果(数据携带)
     *
     * @param resultCode 状态枚举
     * @param data       携带的数据
     */
    public static <T> ResponseResult failure(ResponseResultCode resultCode, T data) {
        return new ResponseResult(resultCode, data);
    }
 
    /**
     * 失败调用返回的结果(无数据携带)
     *
     * @param resultCode 状态枚举
     */
    public static ResponseResult failure(ResponseResultCode resultCode) {
        return failure(resultCode, null);
    }
 
}
package com.lj.miaoskll.response;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
 
@SuppressWarnings("all")
@RestControllerAdvice
@Slf4j
/**
 * 响应增强类,配合{@link JsonResponseResult}实现自定义快速返回
 * beforeBodyWrite在{@link org.springframework.web.bind.annotation.ResponseBody}完成return之后并在消息解析器之前执行
 */
public class JsonResponseParse implements ResponseBodyAdvice {
 
    @Override
    /**
     * 返回值决定他是否需要进入beforeBodyWrite
     */
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        /*methodParameter是当前执行返回响应的方法,判断在该类上是否存在对应的注解*/
        return methodParameter.getMethod().isAnnotationPresent(JsonResponseResult.class);
    }
 
    @Override
    /**
     * 用于修改返回前的值
     */
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (o == null) {
            return ResponseResult.success();
        }
        if (o instanceof Integer) {
            return ResponseResult.failure(ResponseResultCode.queryCode((Integer) o));
        }
        if (o instanceof ResponseResultCode) {
            return ResponseResult.failure((ResponseResultCode) o);
        }
        if (o instanceof ResponseResult) {
            return o;
        }
        return ResponseResult.success(o);
    }
 
}

与JsonResponseParse配合使用

package com.lj.miaoskll.response;
 
import java.lang.annotation.*;
 
@SuppressWarnings("all")
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.METHOD})
/**
 * 此注解用于配合{@link JsonResponseParse}使用
 */
public @interface JsonResponseResult {
 
}

 密码controller层判断
 

package com.lj.miaoskll.service.impl;
 
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.lj.miaoskll.exception.BusinessException;
import com.lj.miaoskll.model.User;
import com.lj.miaoskll.mapper.UserMapper;
import com.lj.miaoskll.response.ResponseResult;
import com.lj.miaoskll.response.ResponseResultCode;
import com.lj.miaoskll.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lj.miaoskll.valid.MD5Utils;
import com.lj.miaoskll.valid.ValidatorUtils;
import com.lj.miaoskll.vo.UserVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import java.util.Date;
 
/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author lj
 * @since 2022-03-11
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Autowired
private UserMapper userMapper;
    @Override
    public ResponseResult<?> login(UserVo user) {
 
      if(!ValidatorUtils.isMobile(user.getId())){
          throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE);
          //return ResponseResult.failure(ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE);
      }
        if(!StringUtils.isNotBlank(user.getPassword())){
            throw new BusinessException(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
            //return ResponseResult.failure(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
        }
        User u = userMapper.selectOne(new QueryWrapper<User>().eq("id",user.getId()));
        if(u==null){
            //return ResponseResult.failure(ResponseResultCode.USER_ACCOUNT_NOT_FIND);
            throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_FIND);
        }
        String salt = u.getSalt();
        String newpassword = MD5Utils.formPassToDbPass(user.getPassword(),salt);
        if(!u.getPassword().equals(newpassword)){
            throw new BusinessException(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
            //return ResponseResult.failure(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
        }
        this.update(new UpdateWrapper<User>().eq("id",user.getId()).set("last_login_date",new Date()).setSql("login_count=login_count+1"));
        return ResponseResult.success(user);
    }
}

二、全局异常处理

在可能出现异常的地方进行抛出

  BusinessException 类

package com.lj.miaoskll.exception;
 
import com.lj.miaoskll.response.ResponseResultCode;
import lombok.Data;
 
@SuppressWarnings("all")
@Data
public class BusinessException extends RuntimeException {
 
    private ResponseResultCode responseResultCode;
 
    public BusinessException(ResponseResultCode responseResultCode) {
        this.responseResultCode = responseResultCode;
    }
 
}

三、密码盐加密

包括二重 前端->后端  后端->数据库

 前端登录代码(包括解析密码)

layui.define(()=>{
let $=layui.jquery
    let layer=layui.layer
    $(login).click(()=>{
       let id=$("#mobile").val()
        let password=$("#password").val()
        let salt = "f1g2h3j4"
        password = salt.charAt(1) + "" + salt.charAt(5) + password + salt.charAt(0) + "" + salt.charAt(3);
        password=md5(password)
 
        $.ajax({
            url:"/user/login",
            data:{
                id,password
            },
            datatype:"json",
            success(e){
                layer.msg(e.message,{
                    icon: 1,
                    time: 2000 //2秒关闭(如果不配置,默认是3秒)
                })
                console.log(e)
            },
            error(e){
 
            }
 
        })
 
        })
 
 
});

加密工具类

package com.lj.miaoskll.valid;
 
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Component;
 
import java.util.UUID;
 
/**
 * MD5加密
 * 用户端:password=MD5(明文+固定Salt)
 * 服务端:password=MD5(用户输入+随机Salt)
 * 用户端MD5加密是为了防止用户密码在网络中明文传输,服务端MD5加密是为了提高密码安全性,双重保险。
 */
@Component
@SuppressWarnings("all")
public class MD5Utils {
 
    //加密盐,与前端一致
    private static String salt = "f1g2h3j4";
 
    /**
     * md5加密
     *
     * @param src
     * @return
     */
    public static String md5(String src) {
        return DigestUtils.md5Hex(src);
    }
 
    /**
     * 获取加密的盐
     *
     * @return
     */
    public static String createSalt() {
        return UUID.randomUUID().toString().replace("-", "");
    }
 
    /**
     * 将前端的明文密码通过MD5加密方式加密成后端服务所需密码
     * 注意:该步骤实际是在前端完成!!!
     *
     * @param inputPass 明文密码
     * @return
     */
    public static String inputPassToFormpass(String inputPass) {
        //混淆固定盐salt,安全性更可靠
        String str = salt.charAt(1) + "" + salt.charAt(5) + inputPass + salt.charAt(0) + "" + salt.charAt(3);
        return md5(str);
    }
 
    /**
     * 将后端密文密码+随机salt生成数据库的密码
     *
     * @param formPass
     * @param salt
     * @return
     */
    public static String formPassToDbPass(String formPass, String salt) {
        //混淆固定盐salt,安全性更可靠
        String str = salt.charAt(7) + "" + salt.charAt(9) + formPass + salt.charAt(1) + "" + salt.charAt(5);
        return md5(str);
    }
 
    /**
     * 将用户输入的密码转换成数据库的密码
     *
     * @param inputPass 明文密码
     * @param salt      盐
     * @return
     */
    public static String inputPassToDbPass(String inputPass, String salt) {
        String formPass = inputPassToFormpass(inputPass);
        String dbPass = formPassToDbPass(formPass, salt);
        return dbPass;
    }
 
    public static void main(String[] args) {
        String formPass = inputPassToFormpass("123456");
        System.out.println("前端加密密码:" + formPass);
        String salt = createSalt();
        System.out.println("后端加密随机盐:" + salt);
        String dbPass = formPassToDbPass(formPass, salt);
        System.out.println("后端加密密码:" + dbPass);
 
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值