您好,登錄后才能下訂單哦!
?最近開發(fā)一個小項目采用springboot2+shiro前后端分離的方式進行。由于訪問使用https證書形式。結(jié)果在上線時遇到登錄信息過期后shiro設(shè)置的跳轉(zhuǎn)接口時重定向為http。從而https訪問http報錯。網(wǎng)上找了很多都沒有一個很好的解決辦法。
? ? 一開始想通過redirectHttp10Compatible:解決https環(huán)境下使用redirect重定向地址變?yōu)閔ttp的協(xié)議,無法訪問服務(wù)的問題??? ? ? ? ? ? 設(shè)置為false,即關(guān)閉了對http1.0協(xié)議的兼容支持 ,實際測試不管用。只能從shiro源碼進行分析如下:
Java代碼
publicboolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
}
可以發(fā)現(xiàn)他是調(diào)用的isAccessAllowed方法和onAccessDenied方法,只要兩者有一個可以就可以了,從名字中我們也可以理解,他的邏輯是這樣:先調(diào)用isAccessAllowed,如果返回的是true,則直接放行執(zhí)行后面的filter和servlet,如果返回的是false,則繼續(xù)執(zhí)行后面的onAccessDenied方法,如果后面返回的是true則也可以有權(quán)限繼續(xù)執(zhí)行后面的filter和servelt。
只有兩個函數(shù)都返回false才會阻止后面的filter和servlet的執(zhí)行。
isAccessAllowed方法在這個類中都是抽象的,依靠實現(xiàn)類實現(xiàn)。onAccessDenied方法不是抽象的,但是調(diào)用了另一個抽象的方法:
org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(ServletRequest, ServletResponse)
這個方法忽略了之前配置的param參數(shù)。
這個類中還有其他的屬性,比如getLoginUrl,這個很容易猜測,是當(dāng)沒有登錄的時候重定向到登錄界面的,這個方法就是獲得登錄界面的位置,默認是/login.jsp,如果我們的登錄界面不是這個的話就要重寫這個方法。
還有一個特別好使的方法
saveRequestAndRedirectToLogin(ServletRequest, ServletResponse),源碼如下:
Java代碼
protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
saveRequest(request);
redirectToLogin(request, response);
}
顯示保存了當(dāng)前的request,然后重定向。
源碼如下:
Java代碼
protected void saveRequest(ServletRequest request) {
WebUtils.saveRequest(request);//關(guān)于webutils在別的博客中。
}
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
String loginUrl = getLoginUrl();//重定向的界面就是到登錄頁面。
WebUtils.issueRedirect(request, response, loginUrl); //關(guān)于webutils在別的博客中。
}
我們?nèi)绻谄渌愔行枰囟ㄏ虻脑捑涂梢灾苯邮褂盟腤ebUtils.issueRedirect(request,response,loginUrl)方法了。
找到辦法了只要在onAccessDenied返回未登錄狀態(tài)就好了。
方法一:重寫FormAuthenticationFilter
原理:
假設(shè)在shiro.xml中配置了 /** = authc,而默認authc對應(yīng)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) {
//設(shè)置響應(yīng)頭
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json");
//設(shè)置返回的數(shù)據(jù)
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);
//刷新和關(guān)閉輸出流
out.flush();
out.close();
} else {
//設(shè)置響應(yīng)頭
System.out.println("=========onAccessDenied==========返回json====>>>>");
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json");
//設(shè)置返回的數(shù)據(jù)
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);
//刷新和關(guān)閉輸出流
out.flush();
out.close();
}
return false;
}
}
第二步:ShiroConfig 類中將重寫的MyFormAuthenticationFilter賦予ShiroFilterFactoryBean 代碼如下:
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必須設(shè)置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不設(shè)置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面
// shiroFilterFactoryBean.setLoginUrl("/adminUser/unauth");
// 登錄成功后要跳轉(zhuǎn)的鏈接
shiroFilterFactoryBean.setSuccessUrl("/");
// 未授權(quán)界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/adminUser/unauth");
Map<String, Filter> filtersMap = new HashMap<>();
MyFormAuthenticationFilter authFilter = new MyFormAuthenticationFilter();
filtersMap.put("authc", authFilter);
shiroFilterFactoryBean.setFilters(filtersMap);
// 配置數(shù)據(jù)庫中的resource
Map<String, String> filterChainDefinitionMap = shiroService.loadFilterChainDefinitions();
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
第三步:
將所以的需要攔截的標注為authc,次處的authc和filtersMap.put("authc", authFilter);設(shè)置的對應(yīng)。
這樣shiro判斷到未登錄就進入次攔截器,返回json數(shù)據(jù)給前端避免了重定向url.
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。