1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 单点登录(SSO)实战 基于非对称加密双向RSA + AES加密

单点登录(SSO)实战 基于非对称加密双向RSA + AES加密

时间:2021-09-19 09:42:01

相关推荐

单点登录(SSO)实战 基于非对称加密双向RSA + AES加密

文章目录

前言非对称性加密,双向加密(RSA+AES)单点登录(SSO)解决方案

前言

关于单点登录(SSO)网上也有很多帖子,但是以我个人的角度来看,大多都是一知半解,看完一圈也还是懵的,而且基本上都是理念,实实在在的去实践的基本上没有,而且内容基本上就是一模一样,这篇文章给大家也是提供一个单点登录的解决方案,至少看完和实践完之后,你知道大概怎么去实现,我这种实现方案也只适用于两个服务之间的通信登录,但是我认为哪有那么多的大型服务通信,又不是人人项目皆淘宝

非对称性加密,双向加密(RSA+AES)

本文我们用到了一种构思,在不传递密钥的情况下,完成解密,这被称为"Diffie-Hellman密钥交换算法",也正是因为这个算法的产生,人类终于可以实现非对称加密了,举个例子:

1.B要先生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。

2.A获取B的公钥,然后用它对信息加密。

3.B得到加密后的信息,用私钥解密。

理论上如果公钥加密的信息只有私钥解得开,那么只要私钥不泄漏,通信就是安全的。

觉得文字不理解的,我提供了一个流程图:

本文单点登录就是基于这个流程实现,下面我们来实操非对称性加密,上代码:

AES加密工具类:

public class AESUtil {//生成AES秘钥,然后Base64编码public static String genKeyAES() throws Exception{KeyGenerator keyGen = KeyGenerator.getInstance("AES");keyGen.init(128);SecretKey key = keyGen.generateKey();String base64Str = byte2Base64(key.getEncoded());return base64Str;}//将Base64编码后的AES秘钥转换成SecretKey对象public static SecretKey loadKeyAES(String base64Key) throws Exception{byte[] bytes = base642Byte(base64Key);SecretKeySpec key = new SecretKeySpec(bytes, "AES");return key;}//加密public static byte[] encryptAES(byte[] source, SecretKey key) throws Exception{Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.ENCRYPT_MODE, key);return cipher.doFinal(source);}//解密public static byte[] decryptAES(byte[] source, SecretKey key) throws Exception{Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.DECRYPT_MODE, key);return cipher.doFinal(source);}//字节数组转Base64编码public static String byte2Base64(byte[] bytes){BASE64Encoder encoder = new BASE64Encoder();return encoder.encode(bytes);}//Base64编码转字节数组public static byte[] base642Byte(String base64Key) throws IOException{BASE64Decoder decoder = new BASE64Decoder();return decoder.decodeBuffer(base64Key);}}

RSA加密工具类:

public class RSAUtil {//生成秘钥对protected static KeyPair getKeyPair() throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048);KeyPair keyPair = keyPairGenerator.generateKeyPair();return keyPair;}//获取公钥(Base64编码)protected static String getPublicKey(KeyPair keyPair){PublicKey publicKey = keyPair.getPublic();byte[] bytes = publicKey.getEncoded();return byte2Base64(bytes);}//获取私钥(Base64编码)protected static String getPrivateKey(KeyPair keyPair){PrivateKey privateKey = keyPair.getPrivate();byte[] bytes = privateKey.getEncoded();return byte2Base64(bytes);}//将Base64编码后的公钥转换成PublicKey对象public static PublicKey string2PublicKey(String pubStr) throws Exception{byte[] keyBytes = base642Byte(pubStr);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey publicKey = keyFactory.generatePublic(keySpec);return publicKey;}//将Base64编码后的私钥转换成PrivateKey对象public static PrivateKey string2PrivateKey(String priStr) throws Exception{byte[] keyBytes = base642Byte(priStr);PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PrivateKey privateKey = keyFactory.generatePrivate(keySpec);return privateKey;}//公钥加密public static byte[] publicEncrypt(byte[] content, PublicKey publicKey) throws Exception{Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, publicKey);byte[] bytes = cipher.doFinal(content);return bytes;}//私钥解密public static byte[] privateDecrypt(byte[] content, PrivateKey privateKey) throws Exception{Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, privateKey);byte[] bytes = cipher.doFinal(content);return bytes;}//字节数组转Base64编码public static String byte2Base64(byte[] bytes){BASE64Encoder encoder = new BASE64Encoder();return encoder.encode(bytes);}//Base64编码转字节数组public static byte[] base642Byte(String base64Key) throws IOException{BASE64Decoder decoder = new BASE64Decoder();return decoder.decodeBuffer(base64Key);}}

加密解密工具类:

public class ServerEncryptUtil {public static String encrypt(String content,String secretKey) throws Exception{//将Base64编码后的Server公钥转换成PublicKey对象PublicKey serverPublicKey = RSAUtil.string2PublicKey(secretKey);//客户端需要知道服务端的公钥信息//每次都随机生成AES秘钥String aesKeyStr = AESUtil.genKeyAES();SecretKey aesKey = AESUtil.loadKeyAES(aesKeyStr);//用Server公钥加密AES秘钥byte[] encryptAesKey = RSAUtil.publicEncrypt(aesKeyStr.getBytes(), serverPublicKey);//用AES秘钥加密请求内容byte[] encryptRequest = AESUtil.encryptAES(content.getBytes(), aesKey);JSONObject result = new JSONObject();result.put("aesk", RSAUtil.byte2Base64(encryptAesKey).replaceAll("\r\n", ""));result.put("content", RSAUtil.byte2Base64(encryptRequest).replaceAll("\r\n", ""));return result.toString();}//服务器解密APP的请求内容public static String decrypt(String content,String secretKe) throws Exception{JSONObject result = JSONObject.parseObject(content);String encryptAesKeyStr = (String) result.get("aesk");String encryptContent = (String) result.get("content");//将Base64编码后的Server私钥转换成PrivateKey对象PrivateKey serverPrivateKey = RSAUtil.string2PrivateKey(secretKe);//用Server私钥解密AES秘钥byte[] aesKeyBytes = RSAUtil.privateDecrypt(RSAUtil.base642Byte(encryptAesKeyStr), serverPrivateKey);SecretKey aesKey = AESUtil.loadKeyAES(new String(aesKeyBytes));//用AES秘钥解密请求内容byte[] request = AESUtil.decryptAES(RSAUtil.base642Byte(encryptContent), aesKey);return new String(request);}}

Test:

公钥私钥信息

//项目A公钥(Base64编码)public final static String A_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApkixN3Dc6BLzb/V74VpxRXsSIu9AabGmK4xfcPiIqub0JS99a+P6XAOGuiMT2W4p1C8U9MZDRgHjUOrKGcc5ve9uT+U90LiAgwG58YdrklOTwlGvo6Xh4HQLRXMNoGsn6jLGdOV1RIVfWQ5EWfEB1+5v86QarLyfLIJ4ujVQfafEJ4dCwmoNSJk8xqVBAW9tDZlNOOgaZPJuEXVIFEEjIZCkFkFxkomwVNdp79Xewrj0mCybCDVy6Mcx3jOxY0gGwbGgS3YQxDbOpqYna8rcmf6CVJ2GA75sCU61Y8Of244CR5Rwkspbr1Pbf4UNSbVbpxzI08z1jrJvCVYWNQLMwwIDAQAB";//项目A私钥(Base64编码)public final static String A_PRIVATE_KEY = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCmSLE3cNzoEvNv9XvhWnFFexIi70BpsaYrjF9w+Iiq5vQlL31r4/pcA4a6IxPZbinULxT0xkNGAeNQ6soZxzm9725P5T3QuICDAbnxh2uSU5PCUa+jpeHgdAtFcw2gayfqMsZ05XVEhV9ZDkRZ8QHX7m/zpBqsvJ8sgni6NVB9p8Qnh0LCag1ImTzGpUEBb20NmU046Bpk8m4RdUgUQSMhkKQWQXGSibBU12nv1d7CuPSYLJsINXLoxzHeM7FjSAbBsaBLdhDENs6mpidrytyZ/oJUnYYDvmwJTrVjw5/bjgJHlHCSyluvU9t/hQ1JtVunHMjTzPWOsm8JVhY1AszDAgMBAAECggEAFTOHhO4a/GwOJeRC20TQ1G8QrOucZt2DtmG7eYf2xPOVhXg8oZj7vuekMe9vBHYLV0Z5gYwV38M13IdTJV5FenYgtocgDpC3sfxyXN1LVejaGhiYMGFiH2AsX7p/rkh7Wl0G+LiY7xeiRJSRGnakKYf5NjNiQ0v5b49jHTrW/G5G579xHOC0EXJezgKKflD+XXhpBjVCMfzkY8tK+ZT5XnUf2U+I7o9u6G3Y3wky2ajR0GyBigLGwI0mVqyA4ie3ggSiMxotfcDwP1HpV/fK//DPpUgBiUgspFt1NtVcNDxeQlqw3UYakfUn5j3inA4C+fZwAe7VNwZkW2uaCl7HIQKBgQDXE49dGomUrvIXeXt/muUw5sy81sufYxUdGm9slfr8DhyEr0KKdrnKFdLtRPdr0mHnp0mlihE+rQQyQg67qys3c4C4TcLq6PHmtkd6K0+rUDYM2BNltjgd42UA86tchZ5Qu1u7dqxmnExYUb/kXbNk/euOcv1iNkdVGq61AZVhfwKBgQDF7G+4q92AQTjYk1dT0Us5oAkGj4GRs5XMeJB+0jhWRhyNvgXRuKkhMgEjbSogAnywQfD93xDw2nZw2TVFqSS5cGCR+KnwTkQcA2vE2IbduDQRTT9JUQas3EJhZ1Cp+xyXfAQorCQW5TSNfb0LskTnV+aJaM/Yxb32NzPlXksuvQKBgDn9FhxeOVYTTUazBG9FTiI/OFh5+XDCAEFWjVBTp9Yp39qOfnxiwnkQJUy/2Y4CrU8ONbciYL/rWkRKtzo2TnKm+7+1h6ZapE42O1NfNh3UhJ417BTyanL0ipkVGdDaXfMacQM8XgNUhOkTMY/bC7FhHQ/NRTAjvlvd09kN0j71AoGAHKaoWZRPgTRv1TInDxQaDqJzDAcUG5JimfHOAP3Pd/W4RnB+iShxG0QQ1B8GXRHfGOjCyQ1Ud3k4cgePZaEhltKEuDzF5Op/g4qfPCSYCVqT9vk2sxdOnxFXbqA1FhYqwmcKdxTMOKA/ZkgQaLQKs26PCc8pX1josc617Xsj6QUCgYA3sHC9I8fan7FAneJvE1Fsc1ZATMuo/yNA8WlASg+OPgeCgIv5AHAvkKqj3ZYapnafmHJj6L6jUL9dFwKqMncAdVOYI/V0oVoa8wgCHQ6b4S55dWMYhd3hSg8+8mUdxw6oOFL7rpRYduX1KxKc8Y4OuB7RsQgdKlT/sEBDEFdS/w==";//项目B公钥public final static String B_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlNdMH/batOwYmSnTDTJhs2dpEgh9sINPzoCH4cKUw9iesR9FYC4ElRTif5EiL3jVrFvHU0piR11MGrpZigslG76fFL7ukf2uFoqVc2klrS+t5yswwcZGvk64CsOEjzcXLdsbAjkvKQyjaiJ+7SyQdT6GsFYsn+VNFCooCfDqUUbxc1qbdM+XFVhTGFPgFHrVXs3rfh6XaloKmiZb5xhUB7S+M4nLvKPHPSrNXh5e3TVQmM03kBcTpQgkjYegNcGsNU2V2UzK6gCFibxCE5BZr5m7QYwUDRivZftmeax9AtXOkliBgIb64gpQ98sa11+EZUhgCSFPkobtd9LRRG/QSQIDAQAB";//项目B私钥public final static String B_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCU10wf9tq07BiZKdMNMmGzZ2kSCH2wg0/OgIfhwpTD2J6xH0VgLgSVFOJ/kSIveNWsW8dTSmJHXUwaulmKCyUbvp8Uvu6R/a4WipVzaSWtL63nKzDBxka+TrgKw4SPNxct2xsCOS8pDKNqIn7tLJB1PoawViyf5U0UKigJ8OpRRvFzWpt0z5cVWFMYU+AUetVezet+HpdqWgqaJlvnGFQHtL4zicu8o8c9Ks1eHl7dNVCYzTeQFxOlCCSNh6A1waw1TZXZTMrqAIWJvEITkFmvmbtBjBQNGK9l+2Z5rH0C1c6SWIGAhvriClD3yxrXX4RlSGAJIU+Shu130tFEb9BJAgMBAAECggEANUCyo90WcxTl2Cb2tAoKmr2tAh63mafhreietU+BGnEulgCyOa89RHmscCflK0b4bCqKLmq2rwHacNWro5BJPpv9HtcRVHqHBtmejyRXrpcYiVUSpMHkHcLcZj19+B+l02pJR4peLTmwXhDpiMIhDVHJrt2mKa9I3KYYnTXtIBbNfMFs2MCq8hXS2HOH619p9sTukNVezv8lXI224ZXTNxuY9wxTVhRJqtSy17IARaJbfjZlxTWUVxIMxlZtkUeIPd+qeT7bKsp6TGg6iZO3wfV21LKiiV6XFF6wBTeWr3alCXrfIW94ufDg2OLlKDtyAQTCNAcUPv4lFZhCkCypgQKBgQDXpHLi08+WcpTR+nqeYhPxdlapGavvyxKlkj3OxTkXOrZuW3I9y3NIVwUeDpyy1qdIfWYzg7lPqDW005kE5f+hUb3fxeTrbSOyQ5DJlC0DjI413/SIPuUxq4TdozTr7bL8tJr8VEZ50dUkhbMBd4BV99z8PWAGwztGNEnSKpqELQKBgQCwslsrjCcBCt4Ap7E/9kYqgBqeTP9Hld5GPvzdUfI5xvrRQaGHc9uDtmOMab5gCrfxkQgeYuLFVZRLTOTeexyDL/yfiBSWc6FKKLU4ixxmaGzPxe6ieIGR9Z46L+jk8QFn6zEnlRPvn4TMnK0gU+Y7TiocKq6XFuPYqJ57H0HCDQKBgQCq+a5Ffl8nEC5C1nCGR4k8d/F6HeqfM8nTEUKEQQdlDZ47nbHUoQ0EnEpobHl9qof0B8kSqywwplP+zY6TvbCTPXZoiEVbDKuy2bNgwGV4XOccfDcsF4ItgarU+GQrc8noZ2JDEqbWS7LNRFyLmy5b+yxxqlAKzJygqzCkvDbK+QKBgDngEZCv9U6YGqMoShxjNBRTpWRYX/04j3d+xiBP6QEXtau4zYmqXypDIVQqhpq6qAlNsdUSGqj8IPiRFR3yQSKPIzW1wtiMwzWhI8qDdifs6Ecd084PnpEKXGs+qg/jCMza8ly+rar9GuhSITrHgE/IiG51ZH5ElxiuEkrNsCI5AoGAewKq7xXxOYdTH1oJk4fLn1aCMXqQnZfO5t/TBdCdIX34dFYSK/vdSMx07At5FuiNO0NsMlATOB4HOiOszepJygvHxeyNMwBm5+3emgAd+Uyrt68ZFR8QahFFlS5mt4V53Bjip8XufIp7mPBjHeYkMTwHJTuLQRrYD6v8X7VS7sM=";

加密内容String content = "{\"code\":\"encrypt\",\"name\":\"admin\",\"id\":1}";@Testvoid contextLoads()throws Exception{// 项目A >> 使用项目B 公钥加密String encryptDataA = ServerEncryptUtil.encrypt(content,B_PUBLIC_KEY);System.out.println("项目A加密后的数据:"+encryptDataA);// 项目B >> 使用自己的私钥解密String decryptDataA = ServerEncryptUtil.decrypt(encryptDataA,B_PRIVATE_KEY);System.out.println("拿到项目A加密的数据,解密:"+decryptDataA);// 项目B >> 使用项目A 公钥加密String encryptDataB = ServerEncryptUtil.encrypt(content,A_PUBLIC_KEY);System.out.println("项目A加密后的数据:"+encryptDataB);// 项目A >> 使用自己的私钥解密String decryptDataB = ServerEncryptUtil.decrypt(encryptDataB,A_PRIVATE_KEY);System.out.println("拿到项目A加密的数据,解密:"+decryptDataB);}

看到这,相信你应该对流程有一定的了解了,下面说说本文的单点登录解决方案.

单点登录(SSO)解决方案

首先我们先来理一理,一个平台需要从另一个平台,用户是关键,他们一定得有一个共同点,比如登录名,ID

如图:

关于这个可以在A项目中做一个用户联动,在A项目中新增用户时,得到B项目中的所有用户数据,可在A项目中选择,筛选A平台已经存在的用户,这样就存在关联关系,二个平台的用户名是相同的,后续就能通过用户名进行登录.

下面直接贴张图来讲解全流程

很多细节图文贴不下,比如某些需求是,跳转到具体页面,但是这个用户没有功能权限,所以平台B在模拟登入时,需要对这些进行处理,双方交互是需要互相制定规则的,传输格式、验证格式等等,具体代码就没贴出来(你懂得),相信有这个思路,应该不难,有问题欢迎留言

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。