`

跟开涛学shiro遇到异常Cannot find any provider supporting AES/CBC/PKCS5Padding【解决】

阅读更多

在学习shiro中遇到很多问题,网上资料较少,只有硬啃英文,但demo太少,不好理解。ITeye博客中开涛对编写了比较全的系列教程

跟我学Shiro目录贴

,提供给大家学习,感谢开涛。

在学习到第十三章 RememberMe——《跟我学Shiro》的时候,有一个问题困扰了我2天,给开涛留言,至今未回复,功夫不复有心人,今天早上得到了解决。

问题描述:

1.按照开涛的测试过程

测试:
1、访问http://localhost:8080/chapter13/,会跳转到登录页面,登录成功后会设置会话及rememberMe Cookie;
2、关闭浏览器,此时会话cookie将失效;
3、然后重新打开浏览器访问http://localhost:8080/chapter13/,还是可以访问的;
4、如果此时访问http://localhost:8080/chapter13/authenticated.jsp,会跳转到登录页面重新进行身份验证。

 

测试本章节demo时发现记住我功能不能实现,仔细思考为什么呢?

2.查看cookie,仅生成了sid的cookie,没有生成rememberMe,究竟哪里出了问题?

3.debug跟踪源码

public Subject login(Subject subject, AuthenticationToken token) throws 
AuthenticationException {
        AuthenticationInfo info;
        try {
            info = authenticate(token);
        } catch (AuthenticationException ae) {
            try {
                onFailedLogin(token, ae, subject);
            } catch (Exception e) {
                if (log.isInfoEnabled()) {
                    log.info("onFailedLogin method threw an " +
                            "exception.  Logging and propagating original 
AuthenticationException.", e);
                }
            }
            throw ae; //propagate
        }

        Subject loggedIn = createSubject(token, info, subject);

        onSuccessfulLogin(token, info, loggedIn);

        return loggedIn;
    }

 从onSuccessfulLogin(token, info, loggedIn);这里一路逛追,直至

 

private javax.crypto.Cipher newCipherInstance(boolean streaming) throws 
CryptoException {
        String transformationString = getTransformationString(streaming);
        try {
            return javax.crypto.Cipher.getInstance(transformationString);
        } catch (Exception e) {
            String msg = "Unable to acquire a Java JCA Cipher instance using " +
                    javax.crypto.Cipher.class.getName() + ".getInstance( \"" +
 transformationString + "\" ). " +
                    getAlgorithmName() + " under this configuration is required 
for the " +
                    getClass().getName() + " instance to function.";
            throw new CryptoException(msg, e);
        }
    }

 在这里 return javax.crypto.Cipher.getInstance(transformationString);抛出异常:

org.apache.shiro.crypto.CryptoException: Unable to acquire a Java JCA Cipher

 instance using javax.crypto.Cipher.getInstance( "AES/CBC/PKCS5Padding" ).

 AES under this configuration is required for the org.apache.shiro.crypto.

AesCipherService instance to function.
	......
Caused by: java.security.NoSuchAlgorithmException: Cannot find any provider

 supporting AES/CBC/PKCS5Padding
	at javax.crypto.Cipher.getInstance(Cipher.java:523)
	at org.apache.shiro.crypto.JcaCipherService.newCipherInstance
(JcaCipherService.java:408)
	... 28 more

4.不明觉历!!!!!!!!!!!难道是开涛的代码有问题??还是故意设置了障碍要大家学习(实践证明这些假设都是错的)

5.网上查了很多资料,未果,分析源码CookieRememberMeManager继承了AbstractRememberMeManager,在AbstractRememberMeManager中的构造方法中默认初始化了加密算法与设置了默认的cipherKey

 public AbstractRememberMeManager() {
        this.serializer = new DefaultSerializer<PrincipalCollection>();
        this.cipherService = new AesCipherService();
        setCipherKey(DEFAULT_CIPHER_KEY_BYTES);
    }

 

问题的结点可以定在cipherService的实现或者cipherKey的配置上,但很快排除了这一假设。

6.回顾第5章节的例子

@Test
	public void testAesCipherService() {
		CipherService cipherService = new AesCipherService();
		// aesCipherService.setKeySize(128);//设置key长度
		// byte[] key = aesCipherService.generateNewKey().getEncoded();
		// String base64 = Base64.encodeToString(key);
		byte[] key = Base64.decode("4AvVhmFLUs0KTA3Kprsdag==");
		System.out.println("key2==" + key.toString());
		System.out.println(Base64.encodeToString(key));
		// 生成key
		// Key key = aesCipherService.generateNewKey();

		String text = "hello";
		System.out.println(new String(text.getBytes()));
		// 加密
		try {
			String encrptText = cipherService.encrypt(text.getBytes(
), key).toHex();
			System.out.println("encrptText==" + encrptText);
			// 解密
			String text2 = new String(cipherService.decrypt(
Hex.decode(encrptText), key).getBytes());
			System.out.println("text2==" + text2);
			Assert.assertEquals(text, text2);
		} catch (CryptoException e) {
			e.printStackTrace();
		}
	}

 不断调试,右击项目属性--Properties----Java Build Path-----Libraries----JRE System Libraries,修改为jdk_1.7.0.01_x86(名称是添加jre时自定义的),测试代码,可以运行通过。原来是jdk的设置不正确!!!!我的电脑上安装了x86,x64的jdk,平时使用的是x64的版本。

7.以为大功告成,可是……使用jetty启动、使用tomcat启动,测试失败!啊啊啊!!要疯的节奏

8.难道是环境变量也要改过来?修改jdk环境变量%JAVA_HOME%为x86的版本之后,测试成功!终于松了一口气。

记录此问题的解决过程,虽然仅仅是jdk版本的问题,可能安装了x86 jdk的人永远不会遇到,但是还是费了我不少功夫去排除道道屏障,最终拨云见日。

结论:

1.shiro的加密使用javax.crypto.Cipher.getInstance获得实例,不支持64bit的jdk

2.遇到这个错误不用改环境变量,可以通过配置运行时的jre解决

   a)tomcat:window->perferences->server->runtime Env--Edit Server--修改JRE为x86版本

   b)jetty:Debug As--Run Configurations---JRE修改为x86版本

(此问题为电脑上同时安装了x64、x86版本jdk的伙伴记录)

 

 

 

3
4
分享到:
评论
5 楼 aionbo 2017-06-29  
我按你们说的也改成x86了,但还是报同样的错
4 楼 纵观全局 2016-08-06  
完美解决,谢谢
3 楼 Blod123 2016-06-19  
看来 还是一步步跟,我也跟了,只是没有跟到你那么深
2 楼 Long_yuan 2015-06-30  
楼主精神可嘉
1 楼 java-lxm 2015-06-30  
学习了

相关推荐

Global site tag (gtag.js) - Google Analytics