加密算法
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;
}
}