您好,登錄后才能下訂單哦!
?最近開發一個小項目采用springboot2+shiro前后端分離的方式進行。由于訪問使用https證書形式。結果在上線時遇到登錄信息過期后shiro設置的跳轉接口時重定向為http。從而https訪問http報錯。網上找了很多都沒有一個很好的解決辦法。
? ? 一開始想通過redirectHttp10Compatible:解決https環境下使用redirect重定向地址變為http的協議,無法訪問服務的問題??? ? ? ? ? ? 設置為false,即關閉了對http1.0協議的兼容支持 ,實際測試不管用。只能從shiro源碼進行分析如下:
Java代碼
publicboolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
}
可以發現他是調用的isAccessAllowed方法和onAccessDenied方法,只要兩者有一個可以就可以了,從名字中我們也可以理解,他的邏輯是這樣:先調用isAccessAllowed,如果返回的是true,則直接放行執行后面的filter和servlet,如果返回的是false,則繼續執行后面的onAccessDenied方法,如果后面返回的是true則也可以有權限繼續執行后面的filter和servelt。
只有兩個函數都返回false才會阻止后面的filter和servlet的執行。
isAccessAllowed方法在這個類中都是抽象的,依靠實現類實現。onAccessDenied方法不是抽象的,但是調用了另一個抽象的方法:
org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(ServletRequest, ServletResponse)
這個方法忽略了之前配置的param參數。
這個類中還有其他的屬性,比如getLoginUrl,這個很容易猜測,是當沒有登錄的時候重定向到登錄界面的,這個方法就是獲得登錄界面的位置,默認是/login.jsp,如果我們的登錄界面不是這個的話就要重寫這個方法。
還有一個特別好使的方法
saveRequestAndRedirectToLogin(ServletRequest, ServletResponse),源碼如下:
Java代碼
protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
saveRequest(request);
redirectToLogin(request, response);
}
顯示保存了當前的request,然后重定向。
源碼如下:
Java代碼
protected void saveRequest(ServletRequest request) {
WebUtils.saveRequest(request);//關于webutils在別的博客中。
}
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
String loginUrl = getLoginUrl();//重定向的界面就是到登錄頁面。
WebUtils.issueRedirect(request, response, loginUrl); //關于webutils在別的博客中。
}
我們如果在其他類中需要重定向的話就可以直接使用它的WebUtils.issueRedirect(request,response,loginUrl)方法了。
找到辦法了只要在onAccessDenied返回未登錄狀態就好了。
方法一:重寫FormAuthenticationFilter
原理:
假設在shiro.xml中配置了 /** = authc,而默認authc對應org.apache.shiro.web.filter.authc.FormAuthenticationFilter過濾器則表示所有路徑都被此過濾器攔截。
第一步:新建一個MyFormAuthenticationFilter類extends FormAuthenticationFilter代碼如下:
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
private static final Logger log = LoggerFactory.getLogger(MyFormAuthenticationFilter.class);
@Override
protected boolean onAccessDenied(ServletRequest request,
ServletResponse response) throws IOException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
Subject subject = getSubject(request, response);
if (subject.getPrincipal() == null) {
//設置響應頭
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json");
//設置返回的數據
ResultMess resultMess = new ResultMess();
resultMess.setCode(-10000);
resultMess.setMsg("未登錄");
resultMess.setSuccess(false);
Gson gson = new Gson();
String result = gson.toJson(resultMess);
//寫回給客戶端
PrintWriter out = httpResponse.getWriter();
out.write(result);
//刷新和關閉輸出流
out.flush();
out.close();
} else {
//設置響應頭
System.out.println("=========onAccessDenied==========返回json====>>>>");
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json");
//設置返回的數據
ResultMess resultMess = new ResultMess();
resultMess.setCode(-10000);
resultMess.setMsg("未登錄");
resultMess.setSuccess(false);
Gson gson = new Gson();
String s = gson.toJson(resultMess);
//寫回給客戶端
PrintWriter out = httpResponse.getWriter();
out.write(s);
//刷新和關閉輸出流
out.flush();
out.close();
}
return false;
}
}
第二步:ShiroConfig 類中將重寫的MyFormAuthenticationFilter賦予ShiroFilterFactoryBean 代碼如下:
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必須設置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面
// shiroFilterFactoryBean.setLoginUrl("/adminUser/unauth");
// 登錄成功后要跳轉的鏈接
shiroFilterFactoryBean.setSuccessUrl("/");
// 未授權界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/adminUser/unauth");
Map<String, Filter> filtersMap = new HashMap<>();
MyFormAuthenticationFilter authFilter = new MyFormAuthenticationFilter();
filtersMap.put("authc", authFilter);
shiroFilterFactoryBean.setFilters(filtersMap);
// 配置數據庫中的resource
Map<String, String> filterChainDefinitionMap = shiroService.loadFilterChainDefinitions();
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
第三步:
將所以的需要攔截的標注為authc,次處的authc和filtersMap.put("authc", authFilter);設置的對應。
這樣shiro判斷到未登錄就進入次攔截器,返回json數據給前端避免了重定向url.
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。