shiro攔截認(rèn)證的全過程記錄
概述
Shiro是apache旗下一個開源安全框架(http://shiro.apache.org/),它將軟件系統(tǒng)的安全認(rèn)證相關(guān)的功能抽取出來,實現(xiàn)用戶身份認(rèn)證,權(quán)限授權(quán)、加密、會話管理等功能,組成了一個通用的安全認(rèn)證框架。使用shiro就可以非??焖俚耐瓿烧J(rèn)證、授權(quán)等功能的開發(fā),降低系統(tǒng)成本。
Shiro框架三大核心對象
說明:
1)Subject :主體對象,負(fù)責(zé)提交用戶認(rèn)證和授權(quán)信息。
2)SecurityManager:安全管理器,負(fù)責(zé)認(rèn)證,授權(quán)等業(yè)務(wù)實現(xiàn)。(核心)
3)Realm:領(lǐng)域?qū)ο?,?fù)責(zé)從數(shù)據(jù)層獲取業(yè)務(wù)數(shù)據(jù)。
shrio 攔截認(rèn)證全過程
?1.FilterRegistrationBean過濾注冊bean
@Bean public FilterRegistrationBean shiroFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new DelegatingFilterProxy("shiroFilter")); //該值缺省為false,表示生命周期由SpringApplicationContext管理,設(shè)置為true則表示由ServletContainer管理 registration.addInitParameter("targetFilterLifecycle", "true"); registration.setEnabled(true); registration.setOrder(Integer.MAX_VALUE - 1); registration.addUrlPatterns("/*"); return registration; }
設(shè)置過濾的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.調(diào)用父類 executeLogin 進(jìn)行登錄驗證
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); 進(jìn)行登錄
login方法被DelegatingSubject重寫
public void login(AuthenticationToken token) throws AuthenticationException { ** Subject subject = this.securityManager.login(this, token); ** }
6.securityManager.login(this, token) login被DefaultSecurityManager
接下來幾步?jīng)]那么重要省略部分
7.ModularRealmAuthenticator AuthenticationInfo 授權(quán)信息獲取方法
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.接下來則進(jìn)入我們自己寫的Realms類 我的類叫Oauth2Realm
/** * 認(rèn)證(登錄時調(diào)用) */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String accessToken = (String) token.getPrincipal(); //根據(jù)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()); //轉(zhuǎn)換成UserDetail對象 UserDetail userDetail = ConvertUtils.sourceToTarget(userEntity, UserDetail.class); //獲取用戶對應(yīng)的部門數(shù)據(jù)權(quán)限 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; }
負(fù)責(zé)獲取用戶信息的方法
這并不是登錄的過程,而是授權(quán)過濾的過程,通過token到數(shù)據(jù)庫查詢是否有這個用戶,且沒有過期,則證明已經(jīng)登錄。
總結(jié)
到此這篇關(guān)于shrio攔截認(rèn)證的文章就介紹到這了,更多相關(guān)shrio攔截認(rèn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springcloud整合到項目中無法啟動報錯Failed to start bean&n
這篇文章主要介紹了springcloud整合到項目中無法啟動報錯Failed to start bean 'eurekaAutoServiceRegistration'問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01Spring運(yùn)行環(huán)境Environment的解析
本文主要介紹了Spring運(yùn)行環(huán)境Environment的解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08SpringBoot整合flyway實現(xiàn)步驟解析
這篇文章主要介紹了SpringBoot整合flyway實現(xiàn)步驟解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08java抓取鼠標(biāo)事件和鼠標(biāo)滾輪事件示例
這篇文章主要介紹了java抓取鼠標(biāo)事件和鼠標(biāo)滾輪事件示例,需要的朋友可以參考下2014-05-05