開源項目Jfinal-shiro-jwt:shiro驗證失敗跳轉位置代碼優先還是配置優先
尋覓
最近幾天一直在尋找jfinal+shiro的結合方式,特別是適配自定義的token驗證方式,自然是希望能找到已經開源的項目,其次再說自我實現代碼。
關于shiro
官方地址:https://shiro.apache.org/
有些文檔還是需要讀一讀的:
官方文檔:https://shiro.apache.org/documentation.html
infoQ介紹文章:https://www.infoq.com/articles/apache-shiro/
jfinal-shiro-jwt
jwt,JSON WEB TOKEN驗證,目前我們使用該種方式進行身份驗證。另外在框架管理系統發展中,希望能嵌入后端的權限管理,所以最近看上了shiro。所以一直在尋覓jfinal+shiro的最佳組合方式。
前些天看了看jfinal-shiro-plugins,是使用-來實現的。
同事發現網上有一個jfinal-shiro-jwt的項目,或許對實現權限管理有所幫助,因此來學習研究一番。
項目地址:https://github.com/perfree/Jfinal-shiro-jwt
保險起見,我把它復制了一份在gitee中:https://gitee.com/wieweicoding/Jfinal-shiro-jwt
clone到本地:
git clone https://gitee.com/wieweicoding/Jfinal-shiro-jwt
然后使用IDE打開項目,等待編譯完成。目錄結果如下圖所示:
除jfinal常規的Controller,程序入口以及配置外,shiro相關的類包括:ShiroDbRealm,ShiroInterceptor,JWTFilter。token轉換相關的類包括JWTToken,JwtUtils。
TestController中有三個接口,如下:
package com.perfree.controller; import java.util.Date; import java.util.HashMap; import java.util.Map; import com.jfinal.core.Controller; import com.perfree.common.AjaxResult; import com.perfree.jwt.JwtUtils; import org.apache.shiro.authz.annotation.RequiresRoles; /** * 測試Controller * @author Perfree */ public class TestController extends Controller{ /** * 首頁 */ public void index() { renderText("這是首頁"); } /** * 登錄頁 */ public void login() { renderText("請登錄"); } /** * 登錄操作 */ public void doLogin() { try { String name = getPara("name"); String password = getPara("password"); if(name.equals("perfree") && password.equals("123456")) { Map
我們看一下shiro.ini的文件內容:
[main] #realm 自定義realm shiroDbRealm=com.perfree.shiro.ShiroDbRealm securityManager.realms = $shiroDbRealm sessionManager=org.apache.shiro.session.mgt.DefaultSessionManager securityManager.sessionManager=$sessionManager securityManager.sessionManager.sessionValidationSchedulerEnabled = false # 退出跳轉路徑 logout.redirectUrl = /login [filters] app_authc = com.perfree.jwt.JWTFilter app_authc.loginUrl = /login # 登錄成功跳轉路徑 可以自己定義 app_authc.successUrl = /index #路徑角色權限設置 [urls] /login = anon /doLogin = anon /resources/** = anon /logout = logout /** = app_authc,roles[admin]
這里我們說一下路徑角色權限設置的含義:
anon:表示無需認證即可訪問,即允許匿名訪問。
authc:需要認證才可訪問。
user:點擊“記住我”功能可訪問。
其實這些含義表示這些訪問路徑指定了過濾器,如anon表示指定了過濾器為AnonymousFilter。
同樣的,app_authc也對應了在配置文件上半部分配置的過濾器:
[filters] app_authc = com.perfree.jwt.JWTFilter app_authc.loginUrl = /login # 登錄成功跳轉路徑 可以自己定義 app_authc.successUrl = /index
運行測試
我們將項目運行起來,程序入口為com.perfree.Main.class
首先,我們嘗試訪問/index接口,如下圖為postman訪問測試:
接口沒有返回預期的內容,而是返回了“請登錄”三個字,這似乎是下面login接口的返回內容,這是怎么一回事呢?
我們可以從配置行/** = app_authc,roles[admin]得到一些啟發。而其對應的配置中有app_authc.loginUrl = /login,那么是否跟這個有關呢?
再讓我們看一下這個過濾器的具體內容:
package com.perfree.jwt; import java.io.IOException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; /** * 自定義Shiro的過濾器 * @author Perfree * */ public class JWTFilter extends BasicHttpAuthenticationFilter { /** * 判斷用戶是否想要登入。 * 檢測header里面是否包含authc字段即可 */ @Override protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) { HttpServletRequest req = (HttpServletRequest) request; String authorization = req.getHeader("authc"); return authorization != null; } /** * 如果攜帶token進行登錄 */ @Override protected boolean executeLogin(ServletRequest request, ServletResponse response){ HttpServletRequest httpServletRequest = (HttpServletRequest) request; String authorization = httpServletRequest.getHeader("authc"); JWTToken token = new JWTToken(authorization); // 提交給realm進行登入,如果錯誤他會拋出異常并被捕獲 getSubject(request, response).login(token); // 如果沒有拋出異常則代表登入成功,返回true return true; } @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { HttpServletResponse resp = (HttpServletResponse)response; Boolean flag = true; //判斷用戶是否攜帶了token if (isLoginAttempt(request, response)) { try { executeLogin(request, response); } catch (Exception e) { flag = false; } if(!flag) { try { resp.sendRedirect("/login"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return flag; }else { //未攜帶token,重定向至登錄頁面 try { resp.sendRedirect("/login"); } catch (IOException e1) { } return false; } } }
我們看到有幾行代碼中有:
resp.sendRedirect("/login");
到底是配置文件在其作用,還是該重定向代碼呢?
我們先打斷點看看:
首先,確實是執行到了具體重定向語句,我們嘗試修改該語句,再來測試一下:
將/login修改為/noLogin,其接口內容如下:
public void noLogin() { renderText("未登錄測試!"); }
重新測試:
首先,我們發現,該過濾器會一直自我循環中,猜測是因為配置文件中配置的/**=app_authc導致重定向/noLogin也會走該過濾器的問題,所以我們在ini中配置:
/noLogin = anon
再次測試:
由此可見,配置與代碼不一時,代碼是要優先于配置設置的。
統一身份認證服務 IAM
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。