前言
之前佬哥给我提了个需求,如何修改Shiro Key
,我们知道Shiro
在高版本key
默认是随机生成的,没有在配置文件中,即使在配置文件中配置了key
,也要重启服务器完成修改也不太好,虽然之前知道可以通过Java Agent
的方式完成修改,但当时没有了解过这个技术,最近刚好学习了Java Agent
,所以抽空完成提过的需求。
实现
我们只要找到Shiro
加载key
部分的代码,将key
的值改掉即可。shiro的解密逻辑在AbstractRememberMeManager#decrypt
中。可以看到解密的key
是从getDecryptionCipherKey()
得到的。
1 | protected byte[] decrypt(byte[] encrypted) { |
getDecryptionCipherKey
是直接返回了decryptionCipherKey
的结果,所以我们可以:
- 修改
getDecryptionCipherKey
函数的返回结果 - 修改
decryptionCipherKey
属性值
1 | public byte[] getDecryptionCipherKey() { |
修改getDecryptionCipherKey
函数的返回结果
修改getDecryptionCipherKey
的agent
实现如下:
1 | public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, |
依赖包坑点
虽然实现本身非常简单,但是在测试的过程中遇到了一个小坑,就是ClassPool
后的代码一直没有执行,调试了很久才发现是因为没有打包javasist
的依赖。
还有一个坑点是因为我刚开始是使用了maven构建项目的,没打包jar是可以正常执行的,打包后会爆找不到AttachNotSupportedException
类的异常,经过排查是因为依赖了Tools.jar
,但这个依赖在pom.xml
中的配置如下:
1 | <dependency> |
可以看到依赖的是本地系统的jar,而非远程下载的jar包,所以在打包的时候没有将这个jar打包进去,最后我是使用了手动将tools.jar
添加Libs
目录中解决了问题。
获取目录问题
由于我是将Attach
和Agent
打包在一个jar包中的,所以要在运行是获取到jar
包的路径并通过loadAgent
函数加载,查阅资料后发现可以通过下面的语句获取。
1 | String agentpath= AttachAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath(); |
但是这样获取的路径是不能直接使用的,在windows下是多了一个/
的,所以我们要把它处理掉。
1 | if(agentpath.contains("C:")||agentpath.contains("D:")||agentpath.contains("E:")){ |
更改加密key
虽然上面已经更改了解密的key,但是如果解密的key和加密的key不一致,那么如果用户正常使用Remeberme记住密码就会导致登录不成功,所以我们我们还要修改加密的key,保证不影响网站的正常使用。
加密的逻辑是在getEncryptionCipherKey
中实现的, 所以我们只要更改这个函数的返回值就可以了。
1 | protected byte[] encrypt(byte[] serialized) { |
所以只要在transform
中再修改下getEncryptionCipherKey
方法的返回值即可。
1 | CtMethod method2 = clazz.getDeclaredMethod("getEncryptionCipherKey"); |
总结
虽然还可以通过修改字段的方式实现,不过既然已经满足了需求,就先不分析另一种方法了。