目录
JWT
Json web token (JWT), 是为了在⽹络应⽤环境间传递声明⽽执⾏的⼀种基于JSON的开放标准((RFC 7519).定义了⼀种简洁的,⾃包含的⽅法⽤于通信双⽅之间以JSON对象的形式安全的传递信息。因为数 字签名的存在,这些信息是可信的,JWT可以使⽤HMAC算法或者是RSA的公私秘钥对进⾏签名。
JWT组成
示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9`.`eyJpZCI6IjU3ZmVmMTY0ZTU0YWY2NGZmYz UzZGJkNSIsInhzcmYiOiI0ZWE1YzUwOGE2NTY2ZTc2MjQwNTQzZjhmZWIwNmZkNDU3Nzc3YmUz OTU0OWM0MDE2NDM2YWZkYTY1ZDIzMzBlIiwiaWF0IjoxNDc2NDI3OTMzfQ`.`PA3QjeyZSUh7H 0GfE0vJaKW4LjKJuC3dVLQiY4hii8s
Header头部
token类型和加密算法
{"alg":"HS256","typ":"JWT"}
Payload负载
存放信息的地⽅,你可以把⽤户 ID 等信息,常⽤的有 iss(签发者),exp(过期时间),sub(⾯向的⽤户),aud(接 收⽅),iat(签发时间)。
{ "iss": "lion1ou JWT", "iat": 1441593502, "exp": 1441594722, "aud": "www.example.com", "sub": "xxx@163.com" }
Signature签名
前⾯两部分都是使⽤ Base64 进⾏编码的,即前端可以解开知道⾥⾯的信息。Signature 需要使⽤编码后的 header 和 payload 以及我们提供的⼀个密钥,然后使⽤ header 中指定的签名算法(HS256)进 ⾏签名。签名的作⽤是保证 JWT 没有被篡改过。
JWT对比传统token认证
传统token认证
JWT认证
传统的授权模式性能低下,每次都需要请求授权服务校验令牌合法性,我们可以利⽤公钥私 钥完成对令牌的加密,如果加密解密成功,则表示令牌合法,如果加密解密失败,则表示令牌⽆ 效不合法,合法则允许访问资源服务器的资源,解密失败,则不允许访问资源服务器资源
JWT使用
公钥和私钥
授权中心和资源中心持有私钥和公钥
授权中心颁发令牌、私钥签名
资源中心验证令牌、公钥验签
公钥和私钥生成 keytool⼯具⽣成公钥私钥证书
keytool -genkeypair -alias xxxx -keyalg RSA -keypass xxxxxx -keystore xxxx.jks -storepass xxxxxx
keytool -importkeystore -srckeystore xxxx.jks -destkeystore xxxx.jks -deststoretype pkcs12
-alias:密钥的别名;-keyalg:使⽤的hash算法; -keypass:密钥的访问密码; -keystore:密钥库⽂件名; -storepass:密钥库的访问密码;
查询证书信息
keytool -list -keystore xxxx.jks
openssl导出公钥
安装 openssl:http://slproweb.com/products/Win32OpenSSL.html
配置环境变量
keytool -list -rfc --keystore xxxx.jks | openssl x509 -inform pem -pubkey
截取保存为public.key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu/0tAUy6igNeEmaCZPG3
FIkt5T2uqecUlA6WNtFRTSosIiQjX0iA9s+LiOqzmCOm7k9JFjMTSRcmaRMjpTMb
dmmBuDvDa92BOp6lGGT4vT3pJABFs6gdktqBMh0WyoLkOILRk9aO1KRQOHqb9Rfu
if3oyiE1tF0dTYp/wR4T8CYd1p19Qu2LLAFwb5kEuzp8HVDcbt/m1C8Rw4eBla8R
FXNpx5dBjQ8hNsTaDg9byNj+PnMVD5ufUDMw7tjG+1NCJotNzVxrrwLfsJYbCHFp
9YQNpE9ZxMivDV6pM0vc6P/jsLQzmtW5eLDwNl+Usz3zoFT3CeBdrFN4P5W0A5tX
IQIDAQAB
-----END PUBLIC KEY-----
JWT测试
oauth2依赖
<!--oauth2-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
测试代码
public class JWTTest {
//⽣成⼀个jwt令牌
@Test
public void testCreateJwt() throws Exception {
//证书⽂件
String key_location = "xxxx.jks";
//密钥库密码
String keystore_password = "xxxxxx";
// 访问证书路径
ClassPathResource resource = new ClassPathResource(key_location);
//密钥⼯⼚
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, keystore_password.toCharArray());
//密钥的密码,此密码和别名要匹配
String keypassword = "xxxxxx";
//密钥别名
String alias = "xxxx";
//密钥对(密钥和公钥)
KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias, keypassword.toCharArray());
//私钥
RSAPrivateKey aPrivate = (RSAPrivateKey) keyPair.getPrivate();
//定义payload信息
Map<String, Object> tokenMap = new HashMap<String, Object>();
tokenMap.put("id", "123");
tokenMap.put("name", "xxxx");
tokenMap.put("roles", "r01,r02");
tokenMap.put("ext", "1");
//⽣成jwt令牌
Jwt jwt = JwtHelper.encode(new ObjectMapper().writeValueAsString(tokenMap), new RsaSigner(aPrivate));
//取出jwt令牌
String token = jwt.getEncoded();
System.out.println(token);
}
//资源服务使⽤公钥验证jwt的合法性,并对jwt解码
@Test
public void testVerify() {
//jwt令牌
String token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHQiOiIxIiwicm9sZXMiOiJyMDEscjAyIiwibmFtZSI6ImNoZHh5emgiLCJpZCI6IjEyMyJ9.sRE_hwXuSW6NXpk8qnhJVxFqHar_p9qfXgayExeaLHzwJ4bR-On4zo1v0o811a9OZpDy5OeRUc9Vf6Z_lU1ob0tSVo6L382Inudld6hftJFf0F5t0vC8bPQ7irLKLa3rHh02QhiU4upkZLScX0SqjDwRXZqibU7hBRqUuyc2m01PA4rM85P7U2tswSyob8rT2LvfK3ZtR0PT4AkgfRlVyPhD2LUeddM7jJSlUIobRdD08gxWZFr6HVco10R2197Xn57ZrkXUZs7AOYT_E2MlbBxEFXAZeWuV3fdMxf8uZ27sLNEncc7pu2PFExbZUPtQjedpbyZkJIcNc3rmQiQtuA";
//公钥
String publickey = "-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu/0tAUy6igNeEmaCZPG3\n" +
"FIkt5T2uqecUlA6WNtFRTSosIiQjX0iA9s+LiOqzmCOm7k9JFjMTSRcmaRMjpTMb\n" +
"dmmBuDvDa92BOp6lGGT4vT3pJABFs6gdktqBMh0WyoLkOILRk9aO1KRQOHqb9Rfu\n" +
"if3oyiE1tF0dTYp/wR4T8CYd1p19Qu2LLAFwb5kEuzp8HVDcbt/m1C8Rw4eBla8R\n" +
"FXNpx5dBjQ8hNsTaDg9byNj+PnMVD5ufUDMw7tjG+1NCJotNzVxrrwLfsJYbCHFp\n" +
"9YQNpE9ZxMivDV6pM0vc6P/jsLQzmtW5eLDwNl+Usz3zoFT3CeBdrFN4P5W0A5tX\n" +
"IQIDAQAB\n" +
"-----END PUBLIC KEY-----";
//校验jwt
Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(publickey));
//获取jwt原始内容
String claims = jwt.getClaims();
System.out.println(claims);
try {
Map<String, String> map = new ObjectMapper().readValue(claims, Map.class);
System.out.println(map.get("name"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
用户角色管理
RBAC模型
RBAC(基于⻆⾊的权限控制 role base access control)是⼀种设计模式,是⽤来设计和管 理权限相关数据的⼀种模型