加密算法

1、可逆加密算法

解释: 加密后, 密文可以反向解密得到密码原文.

1.1、对称加密

文件加密和解密使用相同的密钥,即加密密钥也可以用作解密密钥

解释: 在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊的加密算法处理 后,使其变成复杂的加密密文发送出去,收信方收到密文后,若想解读出原文,则需要 使用加密时用的密钥以及相同加密算法的逆算法对密文进行解密,才能使其回复成可读 明文。在对称加密算法中,使用的密钥只有一个,收发双方都使用这个密钥,这就需要 解密方事先知道加密密钥。

优点: 对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高。

缺点: 没有非对称加密安全.

用途: 一般用于保存用户手机号、身份证等敏感但能解密的信息。

常见的对称加密算法有: AES、DES、3DES、Blowfish、IDEA、RC4、RC5、RC6、HS256

1.2、非对称加密

两个密钥:公开密钥(publickey)和私有密钥,公有密钥加密,私有密钥解密

解释: 同时生成两把密钥:私钥和公钥,私钥隐秘保存,公钥可以下发给信任客户端. 加密与解密: 私钥加密,持有私钥或公钥才可以解密 公钥加密,持有私钥才可解密 签名: 私钥签名, 持有公钥进行验证是否被篡改过.

优点:非对称加密与对称加密相比,其安全性更好;

缺点:非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。

用途:一般用于签名和认证。私钥服务器保存, 用来加密, 公钥客户拿着用于对于令牌或 者签名的解密或者校验使用.

常见的非对称加密算法有: RSA、DSA(数字签名用)、ECC(移动设备用)、RS256 (采用 SHA‐256 的 RSA 签名)

2、不可逆加密算法

解释: 一旦加密就不能反向解密得到密码原文.

种类: Hash加密算法, 散列算法, 摘要算法等

用途:一般用于效验下载文件正确性,一般在网站上下载文件都能见到;存储用户敏感 信息,如密码、 卡号等不可解密的信息。

常见的不可逆加密算法有: MD5、SHA、HMAC

3、Base64编码

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一。Base64编码可用于在 HTTP环境下传递较长的标识信息。采用Base64编码解码具有不可读性,即所编码的数据 不会被人用肉眼所直接看到。注意:Base64只是一种编码方式,不算加密方法。

在线编码工具: http://www.jsons.cn/img2base64/

4、BCrypt

public class TestBcrypt {
​
    public static void main(String[] args) {
​
        for(int i=0;i<10;i++){
            //获取盐
            String gensalt = BCrypt.gensalt();
            System.out.println("盐:"+gensalt);
            //基于当前的盐对密码进行加密
            String saltPassword = BCrypt.hashpw("123456", gensalt);
            System.out.println("加密后的密文:"+saltPassword);
​
            //解密
            boolean checkpw = BCrypt.checkpw("123456", saltPassword);
            System.out.println("密码校验结果:"+checkpw);
        }
​
    }
}

JWT鉴权

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

一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。

头部(Header)

头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以 被表示成一个JSON对象。

{"typ":"JWT","alg":"HS256"}

在头部指明了签名算法是HS256算法。 我们进行BASE64编 码http://base64.xpcha.com/,编码后的字符串如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

载荷(playload)

载荷就是存放有效信息的地方。

定义一个payload:

{"sub":"1234567890","name":"John Doe","admin":true}

然后将其进行base64加密,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

签证(signature)

jwt的第三部分是一个签证信息,

这个签证信息由三部分组成: header (base64后的) payload (base64后的) secret 这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符 串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第 三部分。

TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

将这三部分用.连接成一个完整的字符串,构成了最终的jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

JJWT签发与验证token JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License, 版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它 的大部分复杂性。

官方文档: https://github.com/jwtk/jjwt

1、添加依赖

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

2、测试

@Test
public void createJWT(){
//当前时间
long currentTimeMillis = System.currentTimeMillis();
currentTimeMillis+=1000000L;
Date date = new Date(currentTimeMillis);
JwtBuilder builder= Jwts.builder()
.setId("888") //设置唯一编号
.setSubject("小白")//设置主题 可以是JSON数据
.setIssuedAt(new Date())//设置签发日期
.setExpiration(date)//设置过期时间
.claim("roles","admin")//设置角色
.signWith(SignatureAlgorithm.HS256,"itcast");//设置签名 使用HS256算
法,并设置SecretKey(字符串)
//构建 并返回一个字符串
System.out.println( builder.compact() );
    //eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NTc5MDU4MDIsImV4cCI6MTU1NzkwNjgwMiwicm9sZXMiOiJhZG1pbiJ9.AS5Y2fNCwUzQQxXh_QQWMpaB75YqfuK‐2P7VZiCXEJI
}
​
​
​
​
//解析
@Test
public void parseJWT(){
String
compactJwt="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJp
YXQiOjE1NTc5MDU4MDIsImV4cCI6MTU1NzkwNjgwMiwicm9sZXMiOiJhZG1pbiJ9.AS5Y2fNC
wUzQQxXh_QQWMpaB75YqfuK‐2P7VZiCXEJI";
Claims claims =
Jwts.parser().setSigningKey("itcast").parseClaimsJws(compactJwt).getBody(
);
System.out.println(claims);
}
​

3、JwtUtil

/**
 * JWT工具类
 */
public class JwtUtil {
​
    //有效期为
    public static final Long JWT_TTL = 3600000L;// 60 * 60 *1000  一个小时
    //设置秘钥明文
    public static final String JWT_KEY = "itcast";
​
    /**
     * 创建token
     * @param id
     * @param subject
     * @param ttlMillis
     * @return
     */
    public static String createJWT(String id, String subject, Long ttlMillis) {
​
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if(ttlMillis==null){
            ttlMillis=JwtUtil.JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        SecretKey secretKey = generalKey();
​
        JwtBuilder builder = Jwts.builder()
                .setId(id)              //唯一的ID
                .setSubject(subject)   // 主题  可以是JSON数据
                .setIssuer("admin")     // 签发者
                .setIssuedAt(now)      // 签发时间
                .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                .setExpiration(expDate);// 设置过期时间
        return builder.compact();
    }
​
    /**
     * 生成加密后的秘钥 secretKey
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
    
    /**
     * 解析
     *
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }
}

4、Gateway验证

@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        //2.获取响应对象
        ServerHttpResponse response = exchange.getResponse();
​
        //3.判断当前的请求是否为登录请求,如果是,则直接放行
        if (request.getURI().getPath().contains("/admin/login")){
            //放行
            return chain.filter(exchange);
        }
        //4.获取当前的所有请求头信息
        HttpHeaders headers = request.getHeaders();
​
        //5.获取jwt令牌信息
        String jwtToken = headers.getFirst("token");
​
        //6.判断当前令牌是否存在,
        if (StringUtils.isEmpty(jwtToken)){
            //如果不存在,则向客户端返回错误提示信息
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
​
        //6.1 如果令牌存在,解析jwt令牌,判断该令牌是否合法,如果令牌不合法,则向客户端返回错误提示信息
        try {
            //解析令牌
            JwtUtil.parseJWT(jwtToken);
        }catch (Exception e){
            e.printStackTrace();
            //令牌解析失败
            //向客户端返回错误提示信息
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
​
        //6.2 如果令牌合法,则放行
        return chain.filter(exchange);
    }
​
    @Override
    public int getOrder() {
        return 0;
    }
}