jfinal中stateless模式嵌入shiro驗證的實現(xiàn)方式
問題起源
在前些天的文章中,我們了解到困惑了我們好幾天的問題是由于jfinal新版中使用undertowServer方式啟動,其嵌入filter的方式有變動,所以導致網(wǎng)上檢索到的通過web.xml嵌入filter失敗。
在不考慮修改undertowServer的情況下,也就意味著我們需要找到一種在undertowServer環(huán)境下,嵌入shiro的方式。
今天,我們就來嘗試一種通過攔截器來實現(xiàn)的Stateless Jfinal 嵌入方式。
Stateless的理解
個人對Stateless的理解就是前后端分離,兩次請求互相獨立,通過約定的token等內(nèi)容判斷是否是同一個用戶。
因此這要求,登錄接口需要給用戶生成一個隨機的token,以便用戶后續(xù)訪問的時候帶上。
登錄接口
登錄接口首先需要我們訪問數(shù)據(jù)庫,以及通過特定算法來驗證用戶名與密碼是否匹配。如果匹配,則生成隨機的字符串,即token,并保存在redis中,注意,映射關(guān)系是token為key,value為用戶信息,可以是用戶名,也可以是用戶id等用戶唯一標識。
@Clear public void Login() { String name = getPara("name"); String password = getPara("password"); if ("admin".equals(name)) { // TODO 判斷密碼與用戶名是否正確 Cache cache = Redis.use(); String token = StrKit.getRandomUUID(); cache.set("TOKEN:" + token, name); renderText(token); } else { renderText("用戶名與密碼錯誤"); } }
另外,需要注意的有兩點:
- 接口前調(diào)用@Clear,即登錄接口不應該被攔截驗證
- 系統(tǒng)的登錄接口,與shiro中的subject.login應該注意區(qū)分,是兩個不同的概念。
自定義攔截器
package com.holdoa.core.interceptor; import com.holdoa.core.controller.BaseController; import com.holdoa.core.filter.JWTToken; import com.jfinal.aop.Interceptor; import com.jfinal.aop.Invocation; import com.jfinal.core.Controller; import com.jfinal.kit.LogKit; import com.jfinal.kit.StrKit; import org.apache.shiro.SecurityUtils; import org.apache.shiro.aop.MethodInvocation; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.aop.AnnotationsAuthorizingMethodInterceptor; import org.apache.shiro.subject.Subject; import java.lang.reflect.Method; public class MyShiroInterceptor extends AnnotationsAuthorizingMethodInterceptor implements Interceptor { public MyShiroInterceptor() { getMethodInterceptors(); } public void intercept(final Invocation inv) { try { String token = inv.getController().getHeader("token"); if (StrKit.isBlank(token)) { BaseController b = (BaseController) inv.getController(); b.renderAppError("缺少token"); return; } else { Subject s = SecurityUtils.getSubject(); JWTToken jwtToken = new JWTToken(token); s.login(jwtToken); inv.invoke(); } } catch (Throwable e) { if (e instanceof AuthorizationException) { doProcessuUnauthorization(inv.getController()); } LogKit.warn("權(quán)限錯誤:", e); try { throw e; } catch (Throwable throwable) { throwable.printStackTrace(); } } } /** * 未授權(quán)處理 * * @param controller controller */ private void doProcessuUnauthorization(Controller controller) { controller.redirect("/login/noLogin"); } }
上面的代碼很長,我們重點看其中的這幾行:
String token = inv.getController().getHeader("token"); if (StrKit.isBlank(token)) { BaseController b = (BaseController) inv.getController(); b.renderAppError("缺少token"); return; } else { Subject s = SecurityUtils.getSubject(); JWTToken jwtToken = new JWTToken(token); s.login(jwtToken); inv.invoke(); }
邏輯可以描述為:獲取token,若不為空,將其轉(zhuǎn)換為JWTToken對象,然后調(diào)用shiro的登錄接口:s.login(jwtToken)
。
而shiro的login方法會觸發(fā)自定義Realm中的驗證接口:
/** * 自定義認證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { String token = (String) auth.getCredentials(); // 解密獲得username,用于和數(shù)據(jù)庫進行對比 String userName = JwtUtils.getUsername(token); if (userName == null || userName == "") { throw new AuthenticationException("token 校驗失敗"); } return new SimpleAuthenticationInfo(token, token, getName()); }
其中,JwtUtils。getUsername的具體代碼如下,和設置token是對應的:
/** * @return token中包含的用戶名 */ public static String getUsername(String token) { Cache cache = Redis.use(); String username = (String)cache.get(RedisKeyPreFix.NEW_OA_MANAGE_TOKEN_PREFIX + token); return username; }
如此,便做到了shiro的嵌入。
遺留問題
目前欠缺的一個問題是,不能實現(xiàn)shiro的注解來進行權(quán)限驗證,這個問題我們還準備借助ShiroPlugin來實現(xiàn),由于jfinal已經(jīng)升級到4.8了,而shiroPlugin目前還停留在支持jfinal 3.x的版本,所以需要我們下載jfianl-shiro-plugin源碼做一些修改。
到此這篇關(guān)于jfinal中stateless模式嵌入shiro驗證的實現(xiàn)方式的文章就介紹到這了,更多相關(guān)jfinal shiro驗證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 如何從list中刪除符合條件的數(shù)據(jù)
這篇文章主要介紹了Java 如何從list中刪除符合條件的數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11mybatisplus的連表增強插件mybatis plus join
本文主要介紹了mybatisplus的連表增強插件mybatis plus join,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-06-06java final 和instanceof 關(guān)鍵字的區(qū)別
這篇文章介紹了java final 和instanceof 關(guān)鍵字的區(qū)別,有需要的朋友可以參考一下2013-09-09Spring復雜對象創(chuàng)建的方式小結(jié)
這篇文章主要介紹了Spring復雜對象創(chuàng)建的三種方式,現(xiàn)在使用Spring如何創(chuàng)建這種類型的對象?Spring中提供了三種方法來創(chuàng)建復雜對象,需要的朋友可以參考下2022-01-01源碼分析Java中ThreadPoolExecutor的底層原理
這篇文章主要帶大家從源碼分析一下Java中ThreadPoolExecutor的底層原理,文中的示例代碼講解詳細,具有一定的學習價值,需要的可以參考一下2023-05-05