Aspose Word Java字节码分析与破解研究

2024-03-02 01:58

本文主要是介绍Aspose Word Java字节码分析与破解研究,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

周六闲来无事,想到之前很容易对aspose.cell v21.4完成破解研究(见博客),但是对aspose.words没有完成破解分析。

这次换个思路,基于License进行class文件分析。

一:从官网下载

下载地址:Java Word Processor API | Aspose.Words for Java;

或者使用maven方式进行jar包下载:

<!-- maven配置 --><repositories><repository><id>AsposeJavaAPI</id><name>Aspose Java API</name><url>https://repository.aspose.com/repo/</url></repository></repositories><dependencies><dependency><groupId>com.aspose</groupId><artifactId>aspose-words</artifactId><version>21.12</version><type>pom</type></dependency></dependencies>

需注意:从官网下载的jar包为实时混淆,混淆的class名各不相同,因此本博客列出关键方法,但是方法名不保证一致。 

二:License安装

见Licensing and Subscription | Documentation

关键代码:

com.aspose.words.License license = new com.aspose.words.License();
license.setLicense("path:\\Aspose.Words.Java.lic");

给出License示例:

<License><Data><LicensedTo>Aspose Scotland Team</LicensedTo><EmailTo>billy.lundie@aspose.com</EmailTo><LicenseType>Developer OEM</LicenseType><LicenseNote>Limited to 1 developer, unlimited physical locations</LicenseNote><OrderID>140408052324</OrderID><UserID>94236</UserID><OEM>This is a redistributable license</OEM><Products><Product>Aspose.Total for Java</Product></Products><EditionType>Enterprise</EditionType><SerialNumber>9a59547c-41f0-428b-ba72-7c4368f151d7</SerialNumber><SubscriptionExpiry>20221231</SubscriptionExpiry><LicenseVersion>3.0</LicenseVersion><LicenseInstructions>http://www.aspose.com/corporate/purchase/license-instructions.aspx</LicenseInstructions></Data><Signature>FO3PHsblgDt8F59sMT1l1amyi9qk2V6E8dQkIP7LdTJSxDibNEFu1zOinQbqFfKv/ruttvcxoROkc1tUe0DtO6cP1Zf6J0VemgSY8i/LZECTGszRqJVQRZ0MoVnBhuPAJk5eli7fhVcF8hWd3E4XQ3LzfmJCuaj2NEteRi5Hrfg=</Signature>
</License>

进入License.class文件,基于IDEA自带反编译功能,我们可以看到源码:下图zzWf9为混淆类,可能每人下载类均不相同,记住该类名。

public class License {public License() {zzZ3T.zzZAj();}public void setLicense(String licenseName) throws Exception {if (licenseName == null) {throw new NullPointerException(zzZ3T.zzZAj().zzMk(new byte[]{105, 108, 101, 99, 115, 110, 78, 101, 109, 97, 101}));} else {(new zzWf9()).zzY98(licenseName, zzZdu.zzXGb());}}public void setLicense(InputStream stream) throws Exception {if (stream == null) {throw new NullPointerException(zzZ3T.zzZAj().zzMk(new byte[]{116, 115, 101, 114, 109, 97}));} else {(new zzWf9()).zzY98(stream);}}
}

可以看到License类中有zzWf9的2个重载方法,关键在于zzY98方法(最后提示混淆方法不保证一致!)。

进入核心验证方法:

void zzY98(InputStream var1) throws Exception {if (var1 == null) {throw new NullPointerException(zzZ3T.zzZAj().zzMk(new byte[]{116, 115, 101, 114, 109, 97}));} else if (!this.zzXvE(var1)) {throw new IllegalStateException(zzZ3T.zzZAj().zzMk(new byte[]{110, 73, 97, 118, 105, 108, 32, 100, 105, 108, 101, 99, 115, 110, 32, 101, 105, 115, 110, 103, 116, 97, 114, 117, 46, 101, 80, 32, 101, 108, 115, 97, 32, 101, 97, 109, 101, 107, 115, 32, 114, 117, 32, 101, 104, 116, 32, 101, 105, 108, 101, 99, 115, 110, 32, 101, 105, 102, 101, 108, 119, 32, 115, 97, 110, 32, 116, 111, 109, 32, 100, 111, 102, 105, 101, 105, 46, 100}));} else {zzWhX var2 = zzWcN;if (var2 == null) {var2 = zzYf8(zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 76, 46, 99, 105, 110, 101, 101, 115, 66, 46, 97, 108, 107, 99, 105, 76, 116, 115}), (String)null);zzWcN = var2;}zzWhX var3 = zzX3l;if (var3 == null) {var3 = zzYf8(zzZ3T.zzZAj().zzMk(new byte[]{111, 67, 104, 110, 108, 111, 97, 100, 101, 116, 76, 46, 99, 105, 110, 101, 101, 115, 66, 46, 97, 108, 107, 99, 105, 76, 116, 115}), zzZDr);zzX3l = var3;}if (zznY.zzZHa() > 0) {throw new IllegalStateException(zzZ3T.zzZAj().zzMk(new byte[]{110, 73, 97, 118, 105, 108, 32, 100, 105, 108, 101, 99, 115, 110, 32, 101, 105, 115, 110, 103, 116, 97, 114, 117, 46, 101, 80, 32, 101, 108, 115, 97, 32, 101, 97, 109, 101, 107, 115, 32, 114, 117, 32, 101, 104, 116, 32, 101, 105, 108, 101, 99, 115, 110, 32, 101, 105, 102, 101, 108, 119, 32, 115, 97, 110, 32, 116, 111, 109, 32, 100, 111, 102, 105, 101, 105, 46, 100}));} else if (!var2.contains(this.zzWO4) && !var3.contains(this.zzWO4)) {boolean var4 = false;String[] var5 = this.zzWJJ;int var6 = var5.length;int var7 = 0;while(var7 < var6) {String var8 = var5[var7];if (!var8.equals(zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 84, 46, 116, 111, 108, 97, 102, 32, 114, 111, 32}) + "Java") && !var8.equals(zzZ3T.zzZAj().zzMk(new byte[]{111, 67, 104, 110, 108, 111, 97, 100, 101, 116, 84, 46, 116, 111, 108, 97, 102, 32, 114, 111, 32}) + "Java")) {if ((var8.equals(zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 84, 46, 116, 111, 108, 97})) || var8.equals(zzZ3T.zzZAj().zzMk(new byte[]{111, 67, 104, 110, 108, 111, 97, 100, 101, 116, 84, 46, 116, 111, 108, 97}))) && "Java".equals(zzZ3T.zzZAj().zzMk(new byte[]{78, 46, 84, 69}))) {var4 = true;break;}if (!var8.equals(zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 84, 46, 116, 111, 108, 97, 80, 32, 111, 114, 117, 100, 116, 99, 70, 32, 109, 97, 108, 105, 121})) && !var8.equals(zzZ3T.zzZAj().zzMk(new byte[]{111, 67, 104, 110, 108, 111, 97, 100, 101, 116, 84, 46, 116, 111, 108, 97, 80, 32, 111, 114, 117, 100, 116, 99, 70, 32, 109, 97, 108, 105, 121}))) {if (var8.equals("Aspose.Words for Java")) {var4 = true;break;}String var9;String var10;if ("Java".equals(zzZ3T.zzZAj().zzMk(new byte[]{78, 46, 84, 69}))) {var9 = "Aspose.Words" + zzZ3T.zzZAj().zzMk(new byte[]{102, 32, 114, 111, 32}) + zzZ3T.zzZAj().zzMk(new byte[]{97, 88, 97, 109, 105, 114, 46, 110, 110, 65, 114, 100, 105, 111, 100});var10 = zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 84, 46, 116, 111, 108, 97, 102, 32, 114, 111, 88, 32, 109, 97, 114, 97, 110, 105, 65, 46, 100, 110, 111, 114, 100, 105});String var11 = "Aspose.Words" + zzZ3T.zzZAj().zzMk(new byte[]{102, 32, 114, 111, 32}) + zzZ3T.zzZAj().zzMk(new byte[]{110, 65, 114, 100, 105, 111, 32, 100, 105, 118, 32, 97, 97, 88, 97, 109, 105, 114, 110});String var12 = zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 84, 46, 116, 111, 108, 97, 102, 32, 114, 111, 65, 32, 100, 110, 111, 114, 100, 105, 118, 32, 97, 105, 88, 32, 109, 97, 114, 97, 110, 105});String var13 = "Aspose.Words" + zzZ3T.zzZAj().zzMk(new byte[]{102, 32, 114, 111, 32}) + zzZ3T.zzZAj().zzMk(new byte[]{79, 105, 32, 83, 105, 118, 32, 97, 97, 88, 97, 109, 105, 114, 110});String var14 = zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 84, 46, 116, 111, 108, 97, 102, 32, 114, 111, 105, 32, 83, 79, 118, 32, 97, 105, 88, 32, 109, 97, 114, 97, 110, 105});String var15 = "Aspose.Words" + zzZ3T.zzZAj().zzMk(new byte[]{102, 32, 114, 111, 32}) + zzZ3T.zzZAj().zzMk(new byte[]{97, 77, 32, 99, 105, 118, 32, 97, 97, 88, 97, 109, 105, 114, 110});String var16 = zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 84, 46, 116, 111, 108, 97, 102, 32, 114, 111, 77, 32, 99, 97, 118, 32, 97, 105, 88, 32, 109, 97, 114, 97, 110, 105});if (var8.equals(var9) || var8.equals(var10) || var8.equals(var11) || var8.equals(var12) || var8.equals(var13) || var8.equals(var14) || var8.equals(var15) || var8.equals(var16)) {var4 = true;break;}}if ("Java".equals(zzZ3T.zzZAj().zzMk(new byte[]{97, 74, 97, 118, 65, 46, 100, 110, 111, 114, 100, 105}))) {var9 = "Aspose.Words" + zzZ3T.zzZAj().zzMk(new byte[]{102, 32, 114, 111, 32}) + zzZ3T.zzZAj().zzMk(new byte[]{110, 65, 114, 100, 105, 111, 100});var10 = zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 84, 46, 116, 111, 108, 97, 102, 32, 114, 111, 65, 32, 100, 110, 111, 114, 100, 105});if (var8.equals(var9) || var8.equals(var10)) {var4 = true;break;}}if (var8.equals("Aspose.Words") && "Java".equals(zzZ3T.zzZAj().zzMk(new byte[]{78, 46, 84, 69}))) {var4 = true;break;}if (var8.equals("Aspose.Words" + zzZ3T.zzZAj().zzMk(new byte[]{80, 32, 111, 114, 117, 100, 116, 99, 70, 32, 109, 97, 108, 105, 121}))) {var4 = true;break;}++var7;continue;}var4 = true;break;}var4 = true;break;}if (!var4) {throw new IllegalStateException(zzZ3T.zzZAj().zzMk(new byte[]{104, 84, 32, 101, 105, 108, 101, 99, 115, 110, 32, 101, 115, 105, 110, 32, 116, 111, 118, 32, 108, 97, 100, 105, 102, 32, 114, 111, 116, 32, 105, 104, 32, 115, 114, 112, 100, 111, 99, 117, 46, 116}));} else {Date var17 = (new SimpleDateFormat("yyyy.MM.dd")).parse("2021.12.01");if (var17.after(this.zzWec)) {throw new IllegalStateException(this.zzY4i.zzXJX(new byte[]{84, 104, 101, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 32, 105, 110, 99, 108, 117, 100, 101, 100, 32, 105, 110, 32, 116, 104, 105, 115, 32, 108, 105, 99, 101, 110, 115, 101, 32, 97, 108, 108, 111, 119, 115, 32, 102, 114, 101, 101, 32, 117, 112, 103, 114, 97, 100, 101, 115, 32, 117, 110, 116, 105, 108, 32}) + (new SimpleDateFormat(this.zzY4i.zzXJX(new byte[]{100, 100, 32, 77, 77, 77, 32, 121, 121, 121, 121}), Locale.ENGLISH)).format(this.zzWec) + this.zzY4i.zzXJX(new byte[]{44, 32}) + this.zzY4i.zzXJX(new byte[]{98, 117, 116, 32, 116, 104, 105, 115, 32, 118, 101, 114, 115, 105, 111, 110, 32, 111, 102, 32, 116, 104, 101, 32, 112, 114, 111, 100, 117, 99, 116, 32, 119, 97, 115, 32, 114, 101, 108, 101, 97, 115, 101, 100, 32, 111, 110, 32}) + (new SimpleDateFormat(this.zzY4i.zzXJX(new byte[]{100, 100, 32, 77, 77, 77, 32, 121, 121, 121, 121}), Locale.ENGLISH)).format(var17) + this.zzY4i.zzXJX(new byte[]{46, 32}) + this.zzY4i.zzXJX(new byte[]{80, 108, 101, 97, 115, 101, 32, 114, 101, 110, 101, 119, 32, 116, 104, 101, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 32, 111, 114, 32, 117, 115, 101, 32, 97, 32, 112, 114, 101, 118, 105, 111, 117, 115, 32, 118, 101, 114, 115, 105, 111, 110, 32, 111, 102, 32, 116, 104, 101, 32, 112, 114, 111, 100, 117, 99, 116, 46}));} else if ((new Date()).after(this.zzYS9)) {throw new IllegalStateException(zzZ3T.zzZAj().zzMk(new byte[]{104, 84, 32, 101, 105, 108, 101, 99, 115, 110, 32, 101, 97, 104, 32, 115, 120, 101, 105, 112, 101, 114, 46, 100}));} else if (this.zzWec.getYear() < 2099) {this.zzWnu = zzYjw.zzVS4;zzWhV = this;}}} else {throw new IllegalStateException(zzZ3T.zzZAj().zzMk(new byte[]{104, 84, 115, 105, 108, 32, 99, 105, 110, 101, 101, 115, 105, 32, 32, 115, 105, 100, 97, 115, 108, 98, 100, 101, 32, 44, 108, 112, 97, 101, 101, 115, 99, 32, 110, 111, 97, 116, 116, 99, 65, 32, 112, 115, 115, 111, 32, 101, 111, 116, 111, 32, 116, 98, 105, 97, 32, 110, 32, 97, 101, 110, 32, 119, 105, 108, 101, 99, 115, 110, 46, 101}));}}}

这个方法有2个注意点:

1、日期判断硬编码:21.12版本注册日期应为2021.12.01日之后,2099年之前;

2、第4行zzXvE方法进行License校验(因为验证不通过提示就是License Invalid)。

本License内容原为.NET,<Product>Aspose.Total for .NET</Product>,这时signature验证通过,但是本博客修改为<Product>Aspose.Total for Java</Product>,因此在校验时会提示License Invalid。

综上,哎~对了,又到了字节码编辑的时候了。但是接下来有个地方是有难度的,

三、class文件编辑

主要在zzWf9.zzXvE校验方法,其中有2个地方修改:

源码:

private boolean zzXvE(InputStream var1) throws Exception {DocumentBuilderFactory var2 = zzXcV.zzWQB();DocumentBuilder var3 = var2.newDocumentBuilder();Document var4 = var3.parse(var1);Element var5 = var4.getDocumentElement();Element var6 = zzWKk(var5, zzZ3T.zzZAj().zzMk(new byte[]{97, 68, 97, 116}));Element var7 = zzWKk(var5, zzZ3T.zzZAj().zzMk(new byte[]{105, 83, 110, 103, 116, 97, 114, 117, 101}));boolean var8 = zzWxF((Node)var6, (Node)var7);Element var9 = zzWKk(var6, zzZ3T.zzZAj().zzMk(new byte[]{114, 80, 100, 111, 99, 117, 115, 116}));NodeList var10 = var9.getElementsByTagName(zzZ3T.zzZAj().zzMk(new byte[]{114, 80, 100, 111, 99, 117, 116}));this.zzWJJ = new String[var10.getLength()];for(int var11 = 0; var11 < this.zzWJJ.length; ++var11) {this.zzWJJ[var11] = var10.item(var11).getFirstChild().getNodeValue();}this.zzWO4 = zzZqK(var6, zzZ3T.zzZAj().zzMk(new byte[]{101, 83, 105, 114, 108, 97, 117, 78, 98, 109, 114, 101}));this.zzWec = zzWxF(var6, zzZ3T.zzZAj().zzMk(new byte[]{117, 83, 115, 98, 114, 99, 112, 105, 105, 116, 110, 111, 120, 69, 105, 112, 121, 114}));this.zzYS9 = zzWxF(var6, zzZ3T.zzZAj().zzMk(new byte[]{105, 76, 101, 99, 115, 110, 69, 101, 112, 120, 114, 105, 121}));return var8;}

1、zzXvE,方法体第7行,

boolean var8 = zzWxF((Node)var6, (Node)var7);

这一行需要跟踪调试,经多次调试发现最后是由ThreadLocal对象进行控制,列出zzWf9关键调用链:

// 进入方法一:
private static boolean zzWxF(Node var0, Node var1) throws Exception {return zzZp8((Node)var0, (Node)var1, (String)null);}// 进入方法二:
private static boolean zzZp8(Node var0, Node var1, String var2) throws Exception {byte[] var3;if (var0 != null) {StringBuilder var4 = new StringBuilder();zzZp8(var4, var0);var3 = var4.toString().getBytes("UTF-16LE");} else {var3 = new byte[0];}byte[] var6;if (var1 != null) {String var5 = var1.getFirstChild().getNodeValue();var6 = zzZbv.zz3m(var5);} else {var6 = new byte[0];}if (var2 == null) {if (zzWjD(var0)) {var2 = var6.length == 128 ? zzZDr : zzWxc;} else {var2 = var6.length == 128 ? zzYAU : zzX1P;}}return zzZp8(var3, var6, var2);}// 进入方法三:
private static boolean zzZp8(byte[] var0, byte[] var1, String var2) throws Exception {String var3 = zzZ3T.zzZAj().zzMk(new byte[]{81, 65, 66, 65});byte[] var4 = zzZbv.zz3m(var3);byte[] var5 = zzZbv.zz3m(var2);return zzxN.zzZp8(var5, var4, var0, var1);}

 发现进入zzxN.zzZp8方法,列出zzxN调用链:

// 进入方法一:
static boolean zzZp8(byte[] var0, byte[] var1, byte[] var2, byte[] var3) throws Exception {return zzZqK(var0, var1, var2, var3);}// 进入方法二:
private static boolean zzZqK(byte[] var0, byte[] var1, byte[] var2, byte[] var3) throws Exception {boolean var4 = false;if (var3.length != var0.length) {zznY.zzWUu(1);var4 = true;}byte[] var5 = zzZbv.zzXvz(var3);zzZto var6;byte[] var7;byte[] var8 = zzZbv.zzZo9(var7 = zzZbv.zzZp8(var6 = new zzZto(var0, var1), var5), var6.getModulus().bitLength() >> 3);byte[] var9 = zzWxF(var0, var2, var8.length);if (var8.length != var9.length) {var4 = true;} else {for(int var10 = 0; var10 < var8.length; ++var10) {var4 = var4 || var8[var10] != var9[var10];}}zzTq var14;(var14 = new zzTq(var7)).zzYBj(var5.length, var9.length, false);zzXUN var11;(var11 = new zzXUN()).write(var7, 0, var7.length);var14.zzZp8(var11, var9, var5.length);if (var14.zzWw9()) {var5[0] = 0;var5[1] = 17;}zzZ3V var12 = new zzZ3V(var14, var8, true, var14.zzWw9());int[] var13 = new int[var7.length];zzXcS.zzZp8(var7, 0, var13, 0, var7.length);var12.zzZp8(var14);var12.zzZ8j();var12.zzbx(true);var14.zzZ7L(true);zzZ3T.zzZAj().zzMk(new byte[]{50, 49, 52, 51, 54, 53, 56, 55, 48, 57, 66, 65, 68, 67, 70, 69});var12.zzZ8j();var12.zzWs3(zzZ3T.zzZAj().zzMk(new byte[]{115, 65, 111, 112, 101, 115, 87, 46, 114, 111, 115, 100}));return !var4;}

 在该方法中发现返回校验结果了,再次寻找关键代码,经多次调试终于发现倒数第5行:

var12.zzbx(true);

该方法为关键方法,进入zzZ3V.zzbx方法,列出调用链:

final void zzbx(boolean var1) throws Exception {this.zzJu = 0;if (this.zzWza.zzGe() > 0L) {int var2 = (int)this.zzWza.zzGe() / 2 + 1;byte[] var3 = this.zzWza.zzWnM();if (zznY.zzZxN() == 255) {zznY.zzWWo(128);}int var4 = var3.length - 1;for(int var5 = 0; var5 < var2; ++var5) {if ((var3[var4] & 255) == 255) {++this.zzhe;}if (var3[var4] != (byte)this.zzZ3G.zz8A()[var4]) {zznY.zzWUu(128);//注意这行}--var4;}}}

 特别注意这行:zznY.zzWUu(128);

终于来到最后的zznY类:

static void zzWUu(int var0) {zzXKA.set(Integer.valueOf(var0));}

在这一行,需要进行修改使这个ThreadLocal设置值为0(具体请自己调试,后续有>0判断)。

2、zzXvE,最后返回修改为true;

4、总结:

1、zznY.zzWUu修改,每次设置值为0:

static void zzWUu(int var0) {byte var1 = 0;//需自己修改字节码文件zzXKA.set(Integer.valueOf(var1));}

2、zzWf9.zzXvE修改,返回校验结果true:

private boolean zzXvE(InputStream var1) throws Exception {DocumentBuilderFactory var2 = zzXcV.zzWQB();DocumentBuilder var3 = var2.newDocumentBuilder();Document var4 = var3.parse(var1);Element var5 = var4.getDocumentElement();Element var6 = zzWKk(var5, zzZ3T.zzZAj().zzMk(new byte[]{97, 68, 97, 116}));Element var7 = zzWKk(var5, zzZ3T.zzZAj().zzMk(new byte[]{105, 83, 110, 103, 116, 97, 114, 117, 101}));boolean var8 = zzWxF((Node)var6, (Node)var7);Element var9 = zzWKk(var6, zzZ3T.zzZAj().zzMk(new byte[]{114, 80, 100, 111, 99, 117, 115, 116}));NodeList var10 = var9.getElementsByTagName(zzZ3T.zzZAj().zzMk(new byte[]{114, 80, 100, 111, 99, 117, 116}));this.zzWJJ = new String[var10.getLength()];for(int var11 = 0; var11 < this.zzWJJ.length; ++var11) {this.zzWJJ[var11] = var10.item(var11).getFirstChild().getNodeValue();}this.zzWO4 = zzZqK(var6, zzZ3T.zzZAj().zzMk(new byte[]{101, 83, 105, 114, 108, 97, 117, 78, 98, 109, 114, 101}));this.zzWec = zzWxF(var6, zzZ3T.zzZAj().zzMk(new byte[]{117, 83, 115, 98, 114, 99, 112, 105, 105, 116, 110, 111, 120, 69, 105, 112, 121, 114}));this.zzYS9 = zzWxF(var6, zzZ3T.zzZAj().zzMk(new byte[]{105, 76, 101, 99, 115, 110, 69, 101, 112, 120, 114, 105, 121}));return true;//自己修改字节码文件}

修改上述两处,即可完成对Aspose.Words jar破解,需配合License文件。

示例代码:

//读取word文件,保存为PDF文件。
License license = new License();
license.setLicense("E:\\Aspose.License.xml");Document doc = new Document("E:\\Aspose.Crack.docx");SaveOutputParameters parameters = doc.save("E:\\cracked.pdf", SaveOptions.createSaveOptions(SaveFormat.PDF));System.out.println(parameters.getContentType());

 转化后文件,无水印无页码限制:

 

搞定收工。

这篇关于Aspose Word Java字节码分析与破解研究的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/764568

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置