1、先說出現的問題:
項目需要app自定義登錄認證,按照SpringSecurity默認的用戶名和密碼認證方式自定義了token,provider,UserService,UserDetails;登錄成功返回token后,app拿着token去訪問后台資源時,一直提示403未認證,調試代碼發現,每次訪問都要走provider的authcatication方法去數據庫認證;按理說jwtfilter校驗token通過后就不需要再次去數據庫查用戶了,但是現在是每次都要去查一次,這個時候jwt設置的token中是沒有密碼的,當provider去驗證的時候發現沒有密碼就報403認證失敗(認證過后,再次拿token去訪問資源是不應該去數據庫認證的);
2、解決問題:
通過斷點發現,SpringSecurity的認證攔截器中有個方法調用的是Authentication接口的isAuthentication方法,這個方法如果返回的是true,就不去provider中認證了,而這個方法就是在AbstractAuthenticationToken 中定義,這個時候我們看一下自定義的Authentication
public class AppAuthenticationToken extends AbstractAuthenticationToken { private final Object principal; private Object credentials; public AppAuthenticationToken( Object principal, Object credentials,Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; this.credentials = credentials; super.setAuthenticated(true); // must use super, as we override } public AppAuthenticationToken(Object principal, Object credentials) { super(null); this.principal = principal; this.credentials = credentials; setAuthenticated(false); } public Object getCredentials() { return this.credentials; } public Object getPrincipal() { return this.principal; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); credentials = null; } }
看到上面的構造方法中都有setAuthenticated這個方法,這個方法就是給Authentication接口的isAuthentication方法提供參數的;我們只要在jwtfilter中驗證通過了token,就要調用AppAuthenticationToken( Object principal, Object credentials,Collection<? extends GrantedAuthority> authorities)這個構造,告訴SpringScurity認證攔截器,我已經在jwtfilter中校驗過了,你不需要檢驗。這樣就ok了。