登录完整流程(1.在yml配置文件中使用数据,进行类的封装与注入使用)

@ConfigurationProperties注解的使用步骤如下:

  1. 在需要绑定属性的Java类上添加@ConfigurationProperties注解。
  2. 在注解中指定属性的前缀,该前缀对应配置文件中的属性键的前缀。
  3. 定义与配置文件中属性键相对应的字段或方法,并使用注解的方式将它们与配置文件中的属性值进行绑定。

下面是一个示例:

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * jw配置类
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "zzyl.framework.jwt")
public class JwtTokenProperties {

    private String secretKey;//签名密钥
    private Integer ttl;//有效时间
}

在上面的示例中,我们使用@ConfigurationProperties注解将一个名为"MyAppProperties"的Java类与配置文件中的属性进行绑定。通过指定prefix属性为"myapp",我们告诉Spring框架要将以"myapp"为前缀的属性值注入到该类的字段或方法中。

假设在application-jwt.yml配置文件中有以下属性:

zzyl:
  framework:
    jwt:
      secret-key: $2a$10$PVtHnkj86mJgf6li/yron.LRx/cQAlaiZkBJ9BeogCNTryXJRT1YC
      ttl: 3600000

当Spring容器启动时,会自动将配置文件中的属性值注入到MyAppProperties类的对应字段中。我们可以通过在其他的Spring组件中注入MyAppProperties对象来使用这些属性值。

@Component
public class MyComponent {
    @Autowired
    private MyAppProperties myAppProperties;

    public void printProperties() {
        System.out.println(myAppProperties);
    }
}

在上面的示例中,我们在一个Spring组件中注入了MyAppProperties对象,并通过调用printProperties()方法来打印属性值。

通过这种方式,我们可以方便地将配置文件中的属性值注入到Java对象中,实现配置的灵活性和可管理性。

1.BCrypt加密和md5加密的区别及代码示例

对于用户密码的保护,通常都会进行加密。我们通常对密码进行加密,然后存放在数据库中,在用户进行登录的时候,将其输入的密码与数据库中存放的密文进行比较,以验证用户密码是否正确。

BCrypt和MD5介绍

BCrypt加密: 一种加盐的单向Hash,不可逆的加密算法,同一种明文(plaintext),每次加密后的密文都不一样,而且不可反向破解生成明文,破解难度很大。

MD5加密: 是不加盐的单向Hash,不可逆的加密算法,同一个密码经过hash的时候生成的是同一个hash值,在大多数的情况下,有些经过md5加密的方法将会被破解。

Bcrypt生成的密文是60位的。而MD5的是32位的。

目前,MD5和BCrypt比较流行。相对来说,BCrypt比MD5更安全,但加密更慢。
虽然BCrpyt也是输入的字符串+盐,但是与MD5+盐的主要区别是:每次加的盐不同,导致每次生成的结果也不相同。无法比对!
代码示例:

import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.crypto.digest.DigestUtil;

public class PwdTest {

    public static void main(String[] args) {
        //md5加密
        String md5Pswd1 = DigestUtil.md5Hex("123456");
        String md5Pswd2 = DigestUtil.md5Hex("123456");
        System.out.println(md5Pswd1);
        System.out.println(md5Pswd2);

        //BCrypt加密
        String hashpw1 = BCrypt.hashpw("123456", BCrypt.gensalt());
        String hashpw2 = BCrypt.hashpw("123456", BCrypt.gensalt());
        System.out.println(hashpw1);
        System.out.println(hashpw2);

        //验证密码是否正确
        boolean checkpw = BCrypt.checkpw("123456", "$2a$10$QPYqZUGv6w53RWOH3hU.gOc4vIOU4Uysif1e.7sQRDIU3BeQsEcZS");
        System.out.println(checkpw);

    }
}

1.对于jwt进行封装,后续可以直接调用jwt这个类

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;

public class JwtUtil {
    /**
     * 生成jwt,使用Hs256算法, 私匙使用固定秘钥
     *
     * @param secretKey jwt秘钥
     * @param ttl       jwt过期时间(小时)
     * @param claims    设置的信息
     * @return
     */
    public static String createJWT(String secretKey, int ttl, Map<String, Object> claims) {
        // 指定签名的时候使用的签名算法,也就是header那部分
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 设置jwt的body
        JwtBuilder builder = Jwts.builder()
                // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
                .setClaims(claims)
                // 设置签名使用的签名算法和签名使用的秘钥
                .signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
                // 设置过期时间
                .setExpiration(DateUtil.offset(new Date(), DateField.HOUR_OF_DAY, ttl));

        return builder.compact();
    }

    /**
     * Token解密
     *
     * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
     * @param token     加密后的token
     * @return
     */
    public static Claims parseJWT(String secretKey, String token) {
        try {
            // 得到DefaultJwtParser
            Claims claims = Jwts.parser()
                    // 设置签名的秘钥
                    .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
                    // 设置需要解析的jwt
                    .parseClaimsJws(token).getBody();
            return claims;
        } catch (Exception e) {
            //            throw new AccessDeniedException("没有权限,请登录");
            //这里的异常是封装的自定义异常,如果使用这个需要自定义异常,或者直接使用运行时异常,直接抛出就行
            //(备选throw new RuntimeException("没有权限,请登录");)
            throw new BaseException(BasicEnum.LOGIN_LOSE_EFFICACY);
        }
    }

}

2.登录代码逻辑业务层代码

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.zzyl.constant.Constants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.LoginDto;
import com.zzyl.entity.User;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.UserMapper;
import com.zzyl.properties.JwtTokenProperties;
import com.zzyl.service.LoginService;
import com.zzyl.utils.JwtUtil;
import com.zzyl.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private JwtTokenProperties jwtTokenProperties;


    /**
     * 登录
     *
     * @param loginDto
     * @return
     */
    @Override
    public UserVo login(LoginDto loginDto) {

        //根据用户名查询用户表的用户数据
        User user = userMapper.selectByUsername(loginDto.getUsername());

        //判断查询的用户数据是否为空
        if (ObjectUtil.isEmpty(user)) {
            throw new BaseException(BasicEnum.LOGIN_FAIL);
        }

        //判断数据库的密码和前端用户传过来的密码是否一致
//        if (!(loginDto.getPassword().equals(user.getPassword()))) {
//            throw new RuntimeException("用户或密码登录错误");
//        }

        if(BCrypt.checkpw(loginDto.getPassword(),user.getPassword())){
            throw new BaseException(BasicEnum.INCORRECT_PASSWORD);

        }

        //判读当前用户是否为启用状态
        if (user.getDataState().equals(SuperConstant.DATA_STATE_1)) {
            throw new BaseException(BasicEnum.ACCOUNT_DISABLED);

        }

        //创建对象,把user封装到userVo,因为返回值是userVo,所以需要转换
        UserVo userVo = BeanUtil.toBean(user, UserVo.class);

        //密码脱敏,就是对密码进行清空
        userVo.setPassword("");

        //创建map集合,把id放进去,创建map集合,根据用户id进行token的创建
        Map<String, Object> map = new HashMap<>();
        //添加id,数据库里面的id数据
        map.put(Constants.JWT_USERID, userVo.getId());

        //根据用户生成jwt鉴权,  这里就是运用了上述jwt封装好的实体类,传入秘钥,传入时间,传入根据id生成的map集合,就能生成token
        String token = JwtUtil.createJWT(jwtTokenProperties.getSecretKey(), jwtTokenProperties.getTtl(), map);

        //把生成好的token返回给前台
        userVo.setUserToken(token);

        return userVo;
    }
}

2.1解析token (这个是如果想要根据token解析数据就可以使用这个形式去获取用户id,根据id就能拿到当前用户的数据了)

import cn.hutool.core.map.MapUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.zzyl.constant.Constants;
import com.zzyl.properties.JwtTokenProperties;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.MobThreadLocal;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 移动端拦截器
 */
@Component
public class MobileInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtTokenProperties jwtTokenProperties;



    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //1.通过requesr获取token
        String token = request.getHeader(Constants.USER_TOKEN);

        //解析token, 需要获取jwtTokenProperties类.getSecretKey()秘钥,传入token
        Claims claims = JwtUtil.parseJWT(jwtTokenProperties.getSecretKey(), token);


        //获取解析后的id
        Long aLong = MapUtil.get(claims, Constants.JWT_USERID, Long.class);

//(这里有牵扯到本地线程的概念,先不管)
        MobThreadLocal.set(aLong);

        return true;



    }


}

3.登录实现之后就需要进行拦截器的使用,登录和拦截器是相辅相成的,有登陆也必然就有拦截器的概念

import com.zzyl.intercept.MobileInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * WebMvc高级配置类
 */
 //拦截器的注解
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private MobileInterceptor mobileInterceptor;

    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(mobileInterceptor)
                .excludePathPatterns("/customer/user/login")
                .addPathPatterns("/customer/**");
    }



}

在这里插入图片描述

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值