shiro攔截認(rèn)證的全過(guò)程記錄
概述
Shiro是apache旗下一個(gè)開(kāi)源安全框架(http://shiro.apache.org/),它將軟件系統(tǒng)的安全認(rèn)證相關(guān)的功能抽取出來(lái),實(shí)現(xiàn)用戶身份認(rèn)證,權(quán)限授權(quán)、加密、會(huì)話管理等功能,組成了一個(gè)通用的安全認(rèn)證框架。使用shiro就可以非??焖俚耐瓿烧J(rèn)證、授權(quán)等功能的開(kāi)發(fā),降低系統(tǒng)成本。
Shiro框架三大核心對(duì)象
說(shuō)明:
1)Subject :主體對(duì)象,負(fù)責(zé)提交用戶認(rèn)證和授權(quán)信息。
2)SecurityManager:安全管理器,負(fù)責(zé)認(rèn)證,授權(quán)等業(yè)務(wù)實(shí)現(xiàn)。(核心)
3)Realm:領(lǐng)域?qū)ο?,?fù)責(zé)從數(shù)據(jù)層獲取業(yè)務(wù)數(shù)據(jù)。
shrio 攔截認(rèn)證全過(guò)程
?1.FilterRegistrationBean過(guò)濾注冊(cè)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è)置過(guò)濾的bean
2.shiroFilter 實(shí)際過(guò)濾配置bean
@Bean("shiroFilter") public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); //oauth過(guò)濾 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為過(guò)濾類 過(guò)濾對(duì)象處/webjars/** /druid/** /login 外的所有
3.過(guò)濾類Oauth2Filter 繼承 AuthenTicationFilter 重寫(xiě)以下方法
/** * 驗(yàn)證是否有效token * @param request re * @param response res * @return 驗(yàn)證token * @throws Exception */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { //獲取請(qǐng)求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)行登錄驗(yà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重寫(xiě)
public void login(AuthenticationToken token) throws AuthenticationException { ** Subject subject = this.securityManager.login(this, token); ** }
6.securityManager.login(this, token) login被DefaultSecurityManager
接下來(lái)幾步?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 獲取我們自己重寫(xiě)的Realms類,主要用戶獲取用戶信息
8.接下來(lái)則進(jìn)入我們自己寫(xiě)的Realms類 我的類叫Oauth2Realm
/** * 認(rèn)證(登錄時(shí)調(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對(duì)象 UserDetail userDetail = ConvertUtils.sourceToTarget(userEntity, UserDetail.class); //獲取用戶對(duì)應(yīng)的部門數(shù)據(jù)權(quán)限 List<Long> deptIdList = shiroService.getDataScopeList(userDetail.getId()); userDetail.setDeptIdList(deptIdList); //賬號(hào)鎖定 if(userDetail.getStatus() == 0){ throw new LockedAccountException(MessageUtils.getMessage(ErrorCode.ACCOUNT_LOCK)); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDetail, accessToken, getName()); return info; }
負(fù)責(zé)獲取用戶信息的方法
這并不是登錄的過(guò)程,而是授權(quán)過(guò)濾的過(guò)程,通過(guò)token到數(shù)據(jù)庫(kù)查詢是否有這個(gè)用戶,且沒(méi)有過(guò)期,則證明已經(jīng)登錄。
總結(jié)
到此這篇關(guān)于shrio攔截認(rèn)證的文章就介紹到這了,更多相關(guān)shrio攔截認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring Boot+Shiro實(shí)現(xiàn)一個(gè)Http請(qǐng)求的Basic認(rèn)證
- Springboot shiro認(rèn)證授權(quán)實(shí)現(xiàn)原理及實(shí)例
- 基于springboot實(shí)現(xiàn)整合shiro實(shí)現(xiàn)登錄認(rèn)證以及授權(quán)過(guò)程解析
- SpringBoot整合Shiro實(shí)現(xiàn)登錄認(rèn)證的方法
- springmvc+shiro+maven 實(shí)現(xiàn)登錄認(rèn)證與權(quán)限授權(quán)管理
- shiro 認(rèn)證流程操作
相關(guān)文章
springcloud整合到項(xiàng)目中無(wú)法啟動(dòng)報(bào)錯(cuò)Failed to start bean&n
這篇文章主要介紹了springcloud整合到項(xiàng)目中無(wú)法啟動(dòng)報(bào)錯(cuò)Failed to start bean 'eurekaAutoServiceRegistration'問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01java如何實(shí)現(xiàn)多線程的順序執(zhí)行
多線程是java的一種重要技術(shù),但是多線程的運(yùn)行是沒(méi)有絕對(duì)的順序的,那么java如何實(shí)現(xiàn)多線程的順序執(zhí)行,下面就一起來(lái)了解一下2021-05-05Spring運(yùn)行環(huán)境Environment的解析
本文主要介紹了Spring運(yùn)行環(huán)境Environment的解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08SpringBoot整合flyway實(shí)現(xiàn)步驟解析
這篇文章主要介紹了SpringBoot整合flyway實(shí)現(xiàn)步驟解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Java求出任意數(shù)字的各個(gè)位數(shù)之和方式
這篇文章主要介紹了Java求出任意數(shù)字的各個(gè)位數(shù)之和方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01java抓取鼠標(biāo)事件和鼠標(biāo)滾輪事件示例
這篇文章主要介紹了java抓取鼠標(biāo)事件和鼠標(biāo)滾輪事件示例,需要的朋友可以參考下2014-05-05Java遞歸算法詳解(動(dòng)力節(jié)點(diǎn)整理)
Java遞歸算法是基于Java語(yǔ)言實(shí)現(xiàn)的遞歸算法。遞歸算法對(duì)解決一大類問(wèn)題很有效,它可以使算法簡(jiǎn)潔和易于理解。接下來(lái)通過(guò)本文給大家介紹Java遞歸算法相關(guān)知識(shí),感興趣的朋友一起學(xué)習(xí)吧2017-03-03java webApp異步上傳圖片實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了java webApp異步上傳圖片實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11