1024_day04_密码加密与微服务鉴权JWT

1.BCrypt密码加密

密码应该通过哈希算法进行加密。 有很多标准的算法比如SHA或者MD5,结合salt(盐)是一个不错的选择。 Spring Security 提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用BCrypt强 哈希方法来加密密码。

2.优点

BCrypt强哈希方法 每次加密的结果都不一样

3.springBoot中使用BCrypt密码加密登陆操作

(1)坐标导入

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring‐boot‐starter‐security</artifactId>
</dependency>

(2)添加配置类

我们在添加了spring security依赖后,所有的地址都被spring security所控制了

/**
 * 安全配置类
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //.authorizeRequests()所有security权限配置的开始
        //.antMatchers()拦截什么路径  permitAll()表示任何权限都可以访问 ,直接放行所有
        //.anyRequest()任何请求  .authenticated()认证后才能访问
        // .and().csrf().disable(); 使csrf拦截失效
        http
                .authorizeRequests()
                .antMatchers("/**").permitAll()
                .anyRequest().authenticated()
                .and().csrf().disable();
    }
}

(3)修改需要使用加密的工程的Application, 配置bean

@Bean
public BCryptPasswordEncoder bcryptPasswordEncoder(){
  return new BCryptPasswordEncoder();
}

(4)登陆的加密和解密

在注册的时候进行加密

encoder.encode(user.getPassword())

在登陆的时候解密 (需要用户输入后的密码和,数据库加密后的密码)

/**
     * 功能描述:用户登录
     *
     * @author: hdh
     * @date: 2020/2/23 13:00
     */
    public User login(User user) {
        //判断用户名是否存在
        User userLogin = this.userDao.findByMobile(user.getMobile());
        //比对加密后的密码和用户输入的密码是否相同
        if (userLogin != null && encoder.matches(user.getPassword(), userLogin.getPassword())) {
            return userLogin;
        }
        return null;
    }

4.基于JWT的Token认证机制实现

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用 户和服务器之间传递安全可靠的信息。(无状态协议)

一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。 头部(Header) 头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以 被表示成一个JSON对象。

 JwtBuilder jwtBuilder = Jwts.builder()
                //id
                .setId("1")
                //用户名
                .setSubject("hdh")
                //生成token的时间
                .setIssuedAt(new Date())
                //指明签名算法是HS256算法 hudaihui 加密的盐
                .signWith(SignatureAlgorithm.HS256, "hudaihui")
                .setExpiration(new Date(new Date().getTime()+15000))
                //可以自己添加需要的信息
                .claim("role","admin");
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

5.Java的JJWT实现JW

(1)引入依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    < artifactId>jjwt</artifactId>
    <version>0.6.0</version>
</dependency>

(2)使用拦截器和JJWT进行,删除用户权限控制操作,只用admin用户可以进行删除

jjwt产生token和解token的工具类

@ConfigurationProperties("jwt.config")需要配置application.yamml
  jwt:
    config:
      key: hudaihui
      ttl: 3600000
@ConfigurationProperties("jwt.config")
public class JwtUtil {

    private String key ;

    private long ttl ;//一个小时

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public long getTtl() {
        return ttl;
    }

    public void setTtl(long ttl) {
        this.ttl = ttl;
    }

    /**
     * 生成JWT
     *
     * @param id
     * @param subject
     * @return
     */
    public String createJWT(String id, String subject, String roles) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder().setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                .signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
        if (ttl > 0) {
            builder.setExpiration( new Date( nowMillis + ttl));
        }
        return builder.compact();
    }

    /**
     * 解析JWT
     * @param jwtStr
     * @return
     */
    public Claims parseJWT(String jwtStr){
        return  Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwtStr)
                .getBody();
    }

}

(3)springBoot interceptor的编写

需要声明那个是拦截器类

@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
    @Autowired
    private JwtInterceptor jwtInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor).
                addPathPatterns("/**").
                excludePathPatterns("/**/login");
    }
}

拦截器的作用仅仅只是解析所有的请求,把请求头中有token的进行解析

@Component
public class JwtInterceptor implements HandlerInterceptor {

    /**
     * 功能描述:拦截器作用:负责把请求头中有tocker令牌的进行解析
     *
     * @author:hdh
     * @date: 2020/2/23 18:43
     */
    @Autowired
    private JwtUtil jwtUtil;

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

        String header = request.getHeader("Authorization");
        if (!StringUtils.isEmpty(header)) {
            if (header.startsWith("Bearer ")) {
                String token = header.substring(7);
                try {
                    Claims claims = jwtUtil.parseJWT(token);
                    String roles = (String) claims.get("roles");
                    if (roles != null || roles.equals("admin")) {
                        request.setAttribute("admin_claims", roles);
                    }
                    if (roles != null || roles.equals("user")) {
                        request.setAttribute("user_claims", roles);
                    }
                } catch (Exception e) {
                    throw new RuntimeException("令牌过期");
                }
            }
        }
        return true;
    }

}

(4)用户进行登陆时生成token

/**
     * 功能描述:用户登陆
     *
     * @author:hdh
     * @date: 2020/2/23 12:57
     */
    @PostMapping("login")
    public Result login(@RequestBody User user) {
        user = this.userService.login(user);
        if (user == null) {
            return new Result(false, StatusCode.ERROR, "登陆失败");
        }
        String token = jwtUtil.createJWT(user.getId(), user.getMobile(), "user");
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("roles", "user");
        return new Result(true, StatusCode.OK, "登陆成功",map);

    }

(5)用户进行删除操作时判断权限是否满足

 /**
     * 删除
     *
     * @param id
     */
    public void deleteById(String id) {

        String admin_claims = (String) request.getAttribute("admin_claims");
        if (StringUtils.isEmpty(admin_claims)) {
            throw new RuntimeException("权限不足");
        }
        userDao.deleteById(id);
    }

 

上一篇:五:Ansible Roles


下一篇:Jenkins基于Role-based认证权限管理