OIDC--对 JWT标准的id_token进行验证和解密。
来源:互联网 发布:数据分析属于什么行业 编辑:程序博客网 时间:2024/06/03 17:51
记录一下OIDC中id_token的验证
做的一个统一身份认证平台项目,用到了OIDC协议。
其中对OP返回的id_token进行验证的过程,写了一个demo。
用spring-boot写的,环境搭建就省略了,只是一个简单的方法。
package com.example.demo;import com.nimbusds.jose.*;import com.nimbusds.jose.crypto.RSASSASigner;import com.nimbusds.jose.crypto.RSASSAVerifier;import com.nimbusds.jose.jca.JCASupport;import com.nimbusds.jose.jwk.JWK;import com.nimbusds.jose.jwk.KeyUse;import com.nimbusds.jose.jwk.RSAKey;import com.nimbusds.jose.util.Base64URL;import com.nimbusds.jwt.*;import net.minidev.json.JSONObject;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.stereotype.Controller;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import java.util.HashMap;import java.util.Map;/** * @author huangteng * @version 1.0.0 * @description for world peace * @time 15:26 2017/9/27 * @modified by: * @modified time: */@Controller@EnableAutoConfigurationpublic class HelloController { private Map<String, JWSSigner> signers = new HashMap<>(); private Map<String, JWSVerifier> verifiers = new HashMap<>(); @RequestMapping("/hello") @ResponseBody public String hello(){ byte[] bytes = null; String str = "eyJraWQiOiJyc2ExIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiI5MDM0Mi5BU0RGSldGQSIsImF1ZCI6ImNsaWVudCIsImtpZCI6InJzYTEiLCJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODA4MFwvb3BlbmlkLWNvbm5lY3Qtc2VydmVyLXdlYmFwcFwvIiwiZXhwIjoxNTA2NzQwODU5LCJpYXQiOjE1MDY3NDAyNTksImp0aSI6ImY1NmYxYjQ5LTMwNWMtNDhmMC1hODRkLWEzNWYyYzA5M2E3OCJ9.CGncdBpF_NRo1ZOR4JNMfDprdrDSQsrBGquQE8d7Xo5ujA0vHOQranKJFixb_r2qOZNtgez4Yn3NAO8oVRpA1rpwD2QDhJX9sw-JBrAS5_0_C1srHxAqqIF3h4mgZ0gjsXODiYobCJCspSiOQVsw-nxDU21fi5lTLWjaHZeVB4Cxd2InOOYrY-PeF1TKbdY9cxpFxOjLLoZML2O4BoXCAqFYK7nBRzL5iRcp6NOB6oRYzzbi-nG5b2_lUtP_9rsu0rTCwJxUMCbB7sTJU2kVTBZR0fOoi66H0vW_sI1UggxYbJ065JNAutLaGdbFXQHtm2hrTB6DmxTYOuU3fhqOIg"; decryptJWT(str); return "hello world"; } /** * 创建一个解密加密的工具方法 * @param jwk * @return */ public void buildSignersAndVerifiers( JWK jwk ){ if( jwk instanceof RSAKey ){ System.out.println("这是一个采用rsaKey"); /** * 公钥加密,私钥解密 * 这里加密的过程就省略了 */ if( jwk.isPrivate() ){ try{ if (jwk.isPrivate()) { RSASSASigner signer = new RSASSASigner((RSAKey) jwk); signers.put("test", signer); } RSASSAVerifier verifier = new RSASSAVerifier((RSAKey) jwk); verifiers.put("test", verifier); }catch ( Exception e ){ System.out.println( "error: " + e.toString() ); } }else{ System.out.println( "你确定你的是私钥" ); } } } /** * 解密 * @param jwtString * @return */ public Map decryptJWT(String jwtString){ Map map = new HashMap(); if(StringUtils.isEmpty(jwtString)) return null; String kid = "rsa1"; String n = "qt6yOiI_wCoCVlGO0MySsez0VkSqhPvDl3rfabOslx35mYEO-n4ABfIT5Gn2zN-CeIcOZ5ugAXvIIRWv5H55-tzjFazi5IKkOIMCiz5__MtsdxKCqGlZu2zt-BLpqTOAPiflNPpM3RUAlxKAhnYEqNha6-allPnFQupnW_eTYoyuzuedT7dSp90ry0ZcQDimntXWeaSbrYKCj9Rr9W1jn2uTowUuXaScKXTCjAmJVnsD75JNzQfa8DweklTyWQF-Y5Ky039I0VIu-0CIGhXY48GAFe2EFb8VpNhf07DP63p138RWQ1d3KPEM9mYJVpQC68j3wzDQYSljpLf9by7TGw"; String e = "AQAB"; String d = "PvBAngE3kkTnD3yDKo3wCvHJHm20kb9a0FVGLd0s2Y0E_3H2XnZC8-2zPhN6AQTjPhohSDCew20gzm76lyOvMqRiUP2Zpaopa1d2fGvNIQSdM07yKa6EivEYxqPQxa5esoZnexgnb9fom70I8n5OQRNQikwu-az26CsHX2zWMRodzSdN5CXHvb1PV09DmH8azTYwoMElPIqmcTfxiRw2Ov5ucmXXngKRFJgvfUgKd7v4ScBX7sQoQEjWEtt7ta0WvL3Ar5E1RAW4aHxuubZ6AtloxWCf17AAKw03dfP5RDm5TDmgm2B635ecJ7fTvneFmg8W_fdMTPRfBlCGNBp3wQ"; try{ JWT jwt = JWTParser.parse(jwtString); /** * 判断JWT类型 */ if (jwt instanceof SignedJWT){ System.out.println("这是一个签名的jwt"); /** * 判断对RSA算法的支持 */ if(JCASupport.isSupported(JWEAlgorithm.RSA_OAEP) && JCASupport.isSupported(EncryptionMethod.A256GCM)){ System.out.println("提供算法支持"); /** * header * 主要包括 类型:jwt 算法:*** */ JSONObject obj = jwt.getHeader() != null ? jwt.getHeader().toJSONObject() : null; System.out.println(obj); /** * payload * iss: jwt签发者 * sub: jwt所面向的用户 * aud: 接收jwt的一方 * exp: jwt的过期时间,这个过期时间必须要大于签发时间 * nbf: 定义在什么时间之前,该jwt都是不可用的 * iat: jwt的签发时间 * jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。 * 。。。 */ JSONObject payloadHeader = ((SignedJWT) jwt).getPayload().toJSONObject() == null ? null : ((SignedJWT) jwt).getPayload().toJSONObject(); System.out.println(payloadHeader); /** * 签名 = HSA256(Base64(header), Base64(payload), 密钥) * * 如果用RSA算法: * RSA Algorithm for SignedJWT * 获取 n, e, d 然后(n, e)作为公钥,(n, d) 作为私钥 * RSA: * 1. 两个足够大的互质数p, q; * 2. 模运算 n = p * q; * 3. (n, e)作为公钥,e满足1<e< (p-1)(q-1),且与(p-1)(q-1)互质 * 4. (n, d) 作为私钥,d满足d*e % (p-1)(q-1)= 1,%是取余运算 */ JWK RSAjwk = new RSAKey( new Base64URL(n), new Base64URL(e), new Base64URL(d), KeyUse.SIGNATURE, null, JWEAlgorithm.RSA_OAEP, kid, null, null, null, null ); /** * 对jwt进行验证。 */ buildSignersAndVerifiers(RSAjwk); JWSSigner signer = signers.get("test"); JWSVerifier verifier = verifiers.get("test"); if(((SignedJWT) jwt).verify(verifier)){ System.out.println("通过验证"); /** * 外层已经验证了id_token的有效性了 * 再验证签名的有效性,采用解析出 Header, ClimeSet 然后我再签名一次。 * 最后比对前后的签名是不是一样。 */ // 获取算法 String alg = (String)obj.get("alg"); JWSAlgorithm a = JWSAlgorithm.parse(alg); // 获取之前的签名 String pre_sign = jwt.getParsedParts()[2].toString(); // 再次签名 if(signer.supportedJWSAlgorithms().contains(a)){ SignedJWT new_jwt = new SignedJWT(((SignedJWT)jwt).getHeader(), ((SignedJWT)jwt).getJWTClaimsSet()); new_jwt.sign(signer); System.out.println(pre_sign); System.out.println(new_jwt.getSignature().toString()); /** * 比对 */ if(pre_sign.equals(new_jwt.getSignature().toString())){ System.out.println("签名有效"); }else{ System.out.println("失败,签名很可能被篡改了!"); } } }else{ System.out.println("验证失败"); } }else{ System.out.println("不支持算法"); } }else if (jwt instanceof PlainJWT){ System.out.println("这是一个普通的 PlainJWT"); }else if(jwt instanceof EncryptedJWT){ System.out.println("这是一个加密的 EncryptedJWT"); } }catch (Exception es){ System.out.println(es.toString()); } return map; }}
阅读全文
0 0
- OIDC--对 JWT标准的id_token进行验证和解密。
- jwt 的签发 和 jwt 的验证
- 基于JWT实现Token的加密和解密
- 对输入的字符串进行RSA加密和解密处理
- 对字符串进行简单的加密和解密处理
- 对字符串进行SHA1和DES(加密,解密),加密和解密的类
- 基于jwt的token验证
- 对文件进行EFS加密和解密
- 对文件进行EFS加密和解密
- 对文件进行EFS加密和解密
- 对密码进行加密和解密
- js对字符串进行加密和解密
- /** * 对密码进行加密和验证的类 */
- java-对密码进行加密和验证的类
- 以压缩包的形式对文件夹进行加密和解密
- 文件中用tobase() && frombase64() 对密码进行加密和解密遇到的问题
- jwt是和oauth相互不同的两种验证方式么?
- jQuery关于对表单进行验证和验证码的实现
- git命令
- shiro学习随笔【五】自定义生成会话ID--SessionIdGenerator
- BZOJ 2460 元素 (线性基)
- java实现列表的上下移动和置顶操作
- mysql的封锁机制以及读锁和写锁的区别
- OIDC--对 JWT标准的id_token进行验证和解密。
- 洛谷Oj-封锁阳光大学-BFS + 染色
- RFX2401C是 RFaxis开发的第二代CMOS 的SOC射频前端集成IC
- bzoj 1966: [Ahoi2005]VIRUS 病毒检测
- myrocks build 镜像
- Android中的自定义View(一)
- [剑指offer]面试题16:反转链表
- Nexus OSS私服仓库的安装和配置以及与Maven整合配置
- 论文发表流程有哪些