shiro攔截邏輯、springboot集成邏輯

1.shiro攔截入口就是shiro攔截器。

在springmvc,的時候,shiro的攔截邏輯很簡單,就是在web.xml配置相應的shiro攔截器,對請求進行攔截驗證是否,

2.springboot中,其實也一樣,通過配置註解@Configuration,將ShiroFilterFactoryBean和DefaultWebSecurityManager

注入到spring容器中。其中ShiroFilterFactoryBean這個類中將

JwtFilter添加進去,代碼中粉色。DefaultWebSecurityManager,
 @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 攔截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        if(oConvertUtils.isNotEmpty(excludeUrls)){
            String[] permissionUrl = excludeUrls.split(",");
            for(String url : permissionUrl){
                filterChainDefinitionMap.put(url,"anon");
            }
        }
//首頁排除 filterChainDefinitionMap.put("/app/userIndex/**", "anon"); //首頁接口 filterChainDefinitionMap.put("/app/notify/**", "anon"); //首頁接口 filterChainDefinitionMap.put("/app/notifyAliPay/**", "anon"); //首頁接口 //websocket排除 filterChainDefinitionMap.put("/websocket/**", "anon"); filterChainDefinitionMap.put("/newsWebsocket/**", "anon"); // 添加自己的過濾器並且取名爲jwt Map<String, Filter> filterMap = new HashMap<String, Filter>(1); //如果cloudServer爲空 則說明是單體 需要加載跨域配置 Object cloudServer = env.getProperty(CommonConstant.CLOUD_SERVER_KEY); filterMap.put("jwt", new JwtFilter(cloudServer==null)); shiroFilterFactoryBean.setFilters(filterMap); // <!-- 過濾鏈定義,從上向下順序執行,一般將/**放在最爲下邊 filterChainDefinitionMap.put("/**", "jwt"); // 未授權界面返回JSON shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403"); shiroFilterFactoryBean.setLoginUrl("/sys/common/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean("securityManager") public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm); /* * 關閉shiro自帶的session,詳情見文檔 * http://shiro.apache.org/session-management.html#SessionManagement- * StatelessApplications%28Sessionless%29 */ DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); defaultSessionStorageEvaluator.setSessionStorageEnabled(false); subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); securityManager.setSubjectDAO(subjectDAO); //自定義緩存實現,使用redis securityManager.setCacheManager(redisCacheManager()); return securityManager; }

  

JwtFilter類
package org.jeecg.config.shiro.filters;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.config.mybatis.TenantContext;
import org.jeecg.config.shiro.JwtToken;
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.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * @Description: 鑑權登錄攔截器
 * @Author: Scott
 * @Date: 2018/10/7
 **/
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {

    private boolean allowOrigin = true;

    public JwtFilter(){}
    public JwtFilter(boolean allowOrigin){
        this.allowOrigin = allowOrigin;
    }

    /**
     * 執行登錄認證
     *
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        try {
            executeLogin(request, response);
            return true;
        } catch (Exception e) {
            throw new AuthenticationException("Token失效,請重新登錄", e);
        }
    }

    /**
     *
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader(CommonConstant.X_ACCESS_TOKEN);

        JwtToken jwtToken = new JwtToken(token);
        // 提交給realm進行登入,如果錯誤他會拋出異常並被捕獲
        getSubject(request, response).login(jwtToken);
        // 如果沒有拋出異常則代表登入成功,返回true
        return true;
    }

    /**
     * 對跨域提供支持
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        if(allowOrigin){
            httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
            httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
            httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
            //update-begin-author:scott date:20200907 for:issues/I1TAAP 前後端分離,shiro過濾器配置引起的跨域問題
            // 是否允許發送Cookie,默認Cookie不包括在CORS請求之中。設爲true時,表示服務器允許Cookie包含在請求中。
            httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
            //update-end-author:scott date:20200907 for:issues/I1TAAP 前後端分離,shiro過濾器配置引起的跨域問題
        }
        // 跨域時會首先發送一個option請求,這裏我們給option請求直接返回正常狀態
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        //update-begin-author:taoyan date:20200708 for:多租戶用到
        String tenant_id = httpServletRequest.getHeader(CommonConstant.TENANT_ID);
        TenantContext.setTenant(tenant_id);
        //update-end-author:taoyan date:20200708 for:多租戶用到
        try{
            return super.preHandle(request, response);
        }catch (Exception e){
            httpServletResponse.setStatus(HttpStatus.OK.value());
            JSONObject data = new JSONObject();
            data.put("code", 403);
            data.put("message", "Token失效,請重新登錄");
            data.put("success", false);
            data.put("now", new Date().getTime());
            /**獲取OutputStream輸出流*/
            OutputStream outputStream = response.getOutputStream();
            /**設置json返回格式*/
            ((HttpServletResponse) response).setHeader("content-type", "application/json");
            /**將字符轉換成字節數組,指定以UTF-8編碼進行轉換*/
            byte[] dataByteArr = data.toJSONString().getBytes(StandardCharsets.UTF_8);
            /**使用OutputStream流向客戶端輸出字節數組*/
            outputStream.write(dataByteArr);
            return false;
        }

        //return super.preHandle(request, response);
    }
}

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章