溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

sringboot2+shiro json接口形式未登錄時報https中有http請求錯誤

發(fā)布時間:2020-06-27 05:11:46 來源:網(wǎng)絡(luò) 閱讀:1155 作者:zhanfeng00 欄目:開發(fā)技術(shù)

?最近開發(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.

向AI問一下細節(jié)

免責(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)容。

AI