spring boot 集成shiro之a(chǎn)jax返回json數(shù)據(jù)以及跨域

要解決ajax請(qǐng)求返回?cái)?shù)據(jù),問題很簡(jiǎn)單,比如你沒有登錄,去請(qǐng)求數(shù)據(jù)的時(shí)候,shiro指定了一個(gè)登錄界面,會(huì)自動(dòng)重定向那個(gè)界面,使用ajax請(qǐng)求的時(shí)候,需要返回?cái)?shù)據(jù)為json格式這時(shí)候可以這么做:
編寫一個(gè)接口:

@GetMapping("/401")
    public ResultData notLogin(){
        return ResultData.resultMsg(-104,"請(qǐng)先登錄");
    }

然后把登錄url設(shè)置成這個(gè),返回的就是json格式的數(shù)據(jù)了,但是問題來了,當(dāng)你跨域請(qǐng)求的時(shí)候,會(huì)報(bào)錯(cuò),即使你設(shè)置了全局跨域,ajax請(qǐng)求首先會(huì)發(fā)送一個(gè)option請(qǐng)求,測(cè)試該鏈接是否能用,再來請(qǐng)求數(shù)據(jù),這個(gè)時(shí)候,會(huì)報(bào)錯(cuò),說不允許重定向,于是需要再shiro過濾器中改造以下,重繼承FormAuthenticationFilter類,重寫preHandle,onAccessDenied方法

    //判斷是否是option請(qǐng)求,是就直接放行
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            setHeader(httpRequest,httpResponse);
            return true;
        }
        return super.preHandle(request,response);
    }

    /**
     * 在訪問controller前判斷是否登錄,返回json,不進(jìn)行重定向。
     * @param request
     * @param response
     * @return true-繼續(xù)往下執(zhí)行,false-該filter過濾器已經(jīng)處理,不繼續(xù)執(zhí)行其他過濾器
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");
            httpServletResponse.getWriter().write(JSONObject.toJSONString(ResultData.resultMsg(-104,"請(qǐng)先登錄")));
        return false;
    }

然后再權(quán)限配置中,使用自定義的過濾器

package com.sansence.redwine.config;

import com.sansence.redwine.shiro.MyAuthenticationFilter;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @program: shiro03
 * @description: 權(quán)限配置
 * @author: jiang wei
 * @create: 2019-04-24 14:13
 */
//@Configuration
public class ShiroConfig {

    /**
     * 配置接口權(quán)限
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //shiroFilterFactoryBean.setLoginUrl("/admin-info/401");//設(shè)置登錄界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/manager/login.html");//設(shè)置無權(quán)限界面
        //設(shè)置自定義過濾器
        Map<String, Filter> filter = new LinkedHashMap<>();
        filter.put("authc",new ShiroLoginFilter());
        shiroFilterFactoryBean.setFilters(filter);
        Map<String,String> filterMap=new LinkedHashMap<>();
        filterMap.put("/logs/**","authc");
        filterMap.put("/product/**","authc");
        filterMap.put("/admin-info/login","anon");
        filterMap.put("/admin-info/401","anon");
        filterMap.put("/admin-info/**","authc");
        filterMap.put("/adminware/**","authc");
        filterMap.put("/unit/**","authc");
        filterMap.put("/customer/**","authc");
        filterMap.put("/repertory/**","authc");
        filterMap.put("/role/**","authc");
        filterMap.put("/permission/**","authc");
        filterMap.put("/species/**","authc");
        filterMap.put("/user/**","authc");
        filterMap.put("/userrecord/**","authc");
        filterMap.put("/ware/**","authc");
        filterMap.put("/warerecord/**","authc");
        filterMap.put("/**","anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 注入權(quán)限管理
     * @return
     */
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(customRealm());
        return securityManager;
    }

    @Bean
    public CustomRealm customRealm(){
        return new CustomRealm();
    }
}

這個(gè)時(shí)候,你請(qǐng)求數(shù)據(jù),還會(huì)報(bào)錯(cuò),說跨域問題,于是需要繼續(xù)改造,繼續(xù)再自定義過濾器中寫跨域處理,貼過濾器完整代碼

package com.sansence.redwine.config;

import com.alibaba.fastjson.JSONObject;
import com.sansence.redwine.util.ResultData;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
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.IOException;

public class ShiroLoginFilter extends FormAuthenticationFilter {


    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            setHeader(httpRequest,httpResponse);
            return true;
        }
        return super.preHandle(request,response);
    }

    /**
     * 在訪問controller前判斷是否登錄,返回json,不進(jìn)行重定向。
     * @param request
     * @param response
     * @return true-繼續(xù)往下執(zhí)行,false-該filter過濾器已經(jīng)處理,不繼續(xù)執(zhí)行其他過濾器
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        setHeader(httpRequest,httpResponse);
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");
            httpServletResponse.getWriter().write(JSONObject.toJSONString(ResultData.resultMsg(-104,"請(qǐng)先登錄")));
        return false;
    }

    /**
     * 為response設(shè)置header,實(shí)現(xiàn)跨域
     */
    private void setHeader(HttpServletRequest request,HttpServletResponse response){
        //跨域的header設(shè)置
        response.setHeader("Access-control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", "*");
        //防止亂碼,適用于傳輸JSON數(shù)據(jù)
        //Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild
        response.setHeader("Content-Type","application/json;charset=UTF-8");
        response.setStatus(HttpStatus.OK.value());
    }
}

除此之外,還要配置cors,貼上代碼

package com.sansence.redwine.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class CORSConfiguration {
    @Bean
    public WebMvcConfigurer CORSConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("*")
                        .allowedMethods("*")
                        .allowedHeaders("*")
                        //設(shè)置是否允許跨域傳cookie
                        .allowCredentials(true)
                        //設(shè)置緩存時(shí)間,減少重復(fù)響應(yīng)
                        .maxAge(3600);
            }
        };
    }
}

問題解決,可以正常訪問數(shù)據(jù),而且未登錄的時(shí)候是以json格式返回的,無權(quán)限設(shè)置json返回同理繼承PermissionsAuthorizationFilter,實(shí)現(xiàn)方法和驗(yàn)證身份返回json一樣,過濾器perms使用自定義過濾器。
但是最后還有一個(gè)問題,跨域的時(shí)候,ajax請(qǐng)求數(shù)據(jù),是屬于一次性的請(qǐng)求,還是無法驗(yàn)證身份,這時(shí)候需要回傳token,服務(wù)器繼承DefaultWebSecurityManager,重寫里面的方法,來驗(yàn)證token是否可用以及鑒權(quán),
這個(gè)問題,下一章再做講解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容