zoukankan      html  css  js  c++  java
  • 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);
        }

     

  • 相关阅读:
    配合网页滚屏播放,做解说词
    @enable跟@import注解
    组合注解与元注解
    Spring Aware
    https的设计原理
    用信鸽来解释 HTTPS
    http三次握手四次挥手
    一致性哈希
    redis cluster原理
    redis cluster集群搭建
  • 原文地址:https://www.cnblogs.com/asndxj/p/12354219.html
Copyright © 2011-2022 走看看