shiro攔截認證的全過程記錄
概述
Shiro是apache旗下一個開源安全框架(http://shiro.apache.org/),它將軟件系統的安全認證相關的功能抽取出來,實現用戶身份認證,權限授權、加密、會話管理等功能,組成瞭一個通用的安全認證框架。使用shiro就可以非常快速的完成認證、授權等功能的開發,降低系統成本。
Shiro框架三大核心對象
說明:
1)Subject :主體對象,負責提交用戶認證和授權信息。
2)SecurityManager:安全管理器,負責認證,授權等業務實現。(核心)
3)Realm:領域對象,負責從數據層獲取業務數據。
shrio 攔截認證全過程
1.FilterRegistrationBean過濾註冊bean
@Bean public FilterRegistrationBean shiroFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new DelegatingFilterProxy("shiroFilter")); //該值缺省為false,表示生命周期由SpringApplicationContext管理,設置為true則表示由ServletContainer管理 registration.addInitParameter("targetFilterLifecycle", "true"); registration.setEnabled(true); registration.setOrder(Integer.MAX_VALUE - 1); registration.addUrlPatterns("/*"); return registration; }
設置過濾的bean
2.shiroFilter 實際過濾配置bean
@Bean("shiroFilter") public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); //oauth過濾 Map<String, Filter> filters = new HashMap<>(10); filters.put("oauth2", new Oauth2Filter()); shiroFilter.setFilters(filters); Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/webjars/**", "anon"); filterMap.put("/druid/**", "anon"); filterMap.put("/login", "anon"); filterMap.put("/**", "oauth2"); shiroFilter.setFilterChainDefinitionMap(filterMap); return shiroFilter; }
配置oauth2Filter為過濾類 過濾對象處/webjars/** /druid/** /login 外的所有
3.過濾類Oauth2Filter 繼承 AuthenTicationFilter 重寫以下方法
/** * 驗證是否有效token * @param request re * @param response res * @return 驗證token * @throws Exception */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { //獲取請求token,如果token不存在,直接返回401 String token = getRequestToken((HttpServletRequest) request); if(StringUtils.isBlank(token)){ HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setContentType("application/json;charset=utf-8"); httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin()); String json = new Gson().toJson(new Result().error(ErrorCode.UNAUTHORIZED)); httpResponse.getWriter().print(json); return false; } return executeLogin(request, response); }
4.調用父類 executeLogin 進行登錄驗證
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { AuthenticationToken token = this.createToken(request, response); if (token == null) { String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken must be created in order to execute a login attempt."; throw new IllegalStateException(msg); } else { try { Subject subject = this.getSubject(request, response); subject.login(token); return this.onLoginSuccess(token, subject, request, response); } catch (AuthenticationException var5) { return this.onLoginFailure(token, var5, request, response); } } }
5.subject.login(token); 進行登錄
login方法被DelegatingSubject重寫
public void login(AuthenticationToken token) throws AuthenticationException { ** Subject subject = this.securityManager.login(this, token); ** }
6.securityManager.login(this, token) login被DefaultSecurityManager
接下來幾步沒那麼重要省略部分
7.ModularRealmAuthenticator AuthenticationInfo 授權信息獲取方法
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { this.assertRealmsConfigured(); Collection<Realm> realms = this.getRealms(); return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken); }
getRealms 獲取我們自己重寫的Realms類,主要用戶獲取用戶信息
8.接下來則進入我們自己寫的Realms類 我的類叫Oauth2Realm
/** * 認證(登錄時調用) */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String accessToken = (String) token.getPrincipal(); //根據accessToken,查詢用戶信息 SysUserTokenEntity tokenEntity = shiroService.getByToken(accessToken); //token失效 if(tokenEntity == null || tokenEntity.getExpireDate().getTime() < System.currentTimeMillis()){ throw new IncorrectCredentialsException(MessageUtils.getMessage(ErrorCode.TOKEN_INVALID)); } //查詢用戶信息 SysUserEntity userEntity = shiroService.getUser(tokenEntity.getUserId()); //轉換成UserDetail對象 UserDetail userDetail = ConvertUtils.sourceToTarget(userEntity, UserDetail.class); //獲取用戶對應的部門數據權限 List<Long> deptIdList = shiroService.getDataScopeList(userDetail.getId()); userDetail.setDeptIdList(deptIdList); //賬號鎖定 if(userDetail.getStatus() == 0){ throw new LockedAccountException(MessageUtils.getMessage(ErrorCode.ACCOUNT_LOCK)); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDetail, accessToken, getName()); return info; }
負責獲取用戶信息的方法
這並不是登錄的過程,而是授權過濾的過程,通過token到數據庫查詢是否有這個用戶,且沒有過期,則證明已經登錄。
總結
到此這篇關於shrio攔截認證的文章就介紹到這瞭,更多相關shrio攔截認證內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Springboot配置圖片虛擬映射示例代碼
- SpringBoot 整合 Shiro 密碼登錄的實現代碼
- 詳解shrio的認證(登錄)過程
- Spring Boot+Shiro實現一個Http請求的Basic認證
- SpringBoot 整合 Shiro 密碼登錄與郵件驗證碼登錄功能(多 Realm 認證)