springBoot前後端分離項目中shiro的302跳轉問題
springBoot前後端分離項目shiro的302跳轉
項目是使用的springboot ,使用的shiro做的用戶鑒權。在前端請求時當用戶信息失效,session失效的時候,shiro會重定向到配置的login.jsp 頁面,或者是自己配置的logUrl。
因是前後端分離項目,與靜態資源文件分離,固重定向後,接著會404。
經過查找網上配置資料,發現302原因是
- FormAuthenticationFilter中onAccessDenied 方法做瞭相應處理。那知道問題所在,就可以有解決方瞭。
- 重寫 onAccessDenied 方法,針對自己的業務做相應處理,然後在加載過濾器配置的時候添加到配置中。
以下是代碼
增加類ShiroFormAuthenticationFilter 重新方法
package com.oilpay.wallet.shiro; import com.alibaba.fastjson.JSONObject; import com.oilpay.wallet.interceptor.TokenInterceptor; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; /** * * 重寫權限驗證問題,登錄失效後返回狀態碼 * */ public class ShiroFormAuthenticationFilter extends FormAuthenticationFilter { Logger logger = LoggerFactory.getLogger(TokenInterceptor.class); @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { if (isLoginRequest(request, response)) { if (isLoginSubmission(request, response)) { if (logger.isTraceEnabled()) { logger.trace("Login submission detected. Attempting to execute login."); } return executeLogin(request, response); } else { if (logger.isTraceEnabled()) { logger.trace("Login page view."); } //allow them to see the login page ;) return true; } } else { HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse resp = (HttpServletResponse) response; if(req.getMethod().equals(RequestMethod.OPTIONS.name())) { resp.setStatus(HttpStatus.OK.value()); return true; } if (logger.isTraceEnabled()) { logger.trace("Attempting to access a path which requires authentication. Forwarding to the " + "Authentication url [" + getLoginUrl() + "]"); } //前端Ajax請求時requestHeader裡面帶一些參數,用於判斷是否是前端的請求 String test= req.getHeader("test"); if (test!= null || req.getHeader("wkcheck") != null) { //前端Ajax請求,則不會重定向 resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin")); resp.setHeader("Access-Control-Allow-Credentials", "true"); resp.setContentType("application/json; charset=utf-8"); resp.setCharacterEncoding("UTF-8"); PrintWriter out = resp.getWriter(); JSONObject result = new JSONObject(); result.put("message", "登錄失效"); result.put("resultCode", 1000); out.println(result); out.flush(); out.close(); } else { saveRequestAndRedirectToLogin(request, response); } return false; } } }
在過濾器配置中添加
@Bean(name="shiroFilter") public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) { ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(manager); //配置訪問權限 LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<String, String>(); filterChainDefinitionMap.put("/common/logout", "logout"); filterChainDefinitionMap.put("/","anon"); filterChainDefinitionMap.put("/common/login","anon"); filterChainDefinitionMap.put("/common/*","anon"); filterChainDefinitionMap.put("/imageVerifyCode/getCode", "anon"); filterChainDefinitionMap.put("/sendVerifyCode/register", "anon"); filterChainDefinitionMap.put("/sendVerifyCode/resetLoginPwd", "anon"); filterChainDefinitionMap.put("/**", "authc"); //表示需要認證才可以訪問 LinkedHashMap<String, Filter> filtsMap=new LinkedHashMap<String, Filter>(); filtsMap.put("authc",new ShiroFormAuthenticationFilter() ); shiroFilterFactoryBean.setFilters(filtsMap); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; }
至此,可以按照自己的需求做相應處理。
關於shiro 總是302的問題
我的原因是使用瞭authc,由於autuc對應的過濾器FormAuthenticationFilter中onAccessDenied方法返回的值都為false,所以訪問url時會一直進行循環重定向,解決方案:重寫onAccessDenied方法,並註入到shiroFiter中。
附上shiro配置文件
<!-- shiroFilter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <!-- 設定角色的登錄鏈接,這裡為cas登錄頁面的鏈接可配置回調地址 --> <!-- 登錄地址 --> <property name="loginUrl" value="/login.html"/> <!-- 登錄後跳轉到業務頁面 --> <property name="successUrl" value="/index.do"/> <!-- 錯誤頁面 --> <property name="unauthorizedUrl" value="/denied.html"/> <property name="filters"> <map> <!--將重寫瞭的FormAuthenticationFilter.onAccessDenied方法的類註入到其中--> <entry key="authc" value-ref="formAuthenticationFilter"></entry> </map> </property> <property name="filterChainDefinitions"> <value> /login.html=anon <!--配置靜態資源--> /js/**=anon /templates/**=anon /assets/**=anon /css/**=anon <!--權限設置--> /index.do=authc /user/login.do=anon /**=authc </value> </property> </bean> <!-- 重寫FormAuthenticationFilter的onAccessDenied方法的自定義過濾器 --> <bean id="formAuthenticationFilter" class="com.jd.risk.giasys.service.realm.filter.MyFilter" />
重寫onAccessDenied方法
package com.jd.risk.giasys.service.realm.filter; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * Created by jianghaisong on 2017/12/17. */ public class MyFilter extends FormAuthenticationFilter{ private Logger log = LoggerFactory.getLogger(MyFilter.class); protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { //進行重寫,業務邏輯 } }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Spring Boot+Shiro實現一個Http請求的Basic認證
- 基於SpringBoot2的Shiro最簡配置操作(兩個文件)
- SpringBoot配置shiro安全框架的實現
- 解決Springboot整合shiro時靜態資源被攔截的問題
- 關於SpringBoot創建存儲令牌的媒介類和過濾器的問題