shiro異步請求返回JSON響應


shiro異步請求返回JSON響應

需求1:當shiro請求資源,但是沒有進行認證時,默認是進行重定向,現在需要返回JSON響應。注意異步請求,服務器重定向后,ajax拿到的是瀏覽器重定向后的到的頁面源碼。
解決2: 自定義FormAuthenticationFilter。覆蓋onAccessDenied方法。返回JSON字符串。並將自定義的過濾器添加到ShiroFilterFactoryBean,鍵的名稱為authc。
需求2:ShiroFilterFactoryBean用注解時,過濾的urls被寫死在代碼中,需要將urls的配置放到配置文件中。
解決2:
	方法1:ShiroFilterFactoryBean不使用注解方法,而是xml配置注入。@ImportResource("classpath:shiro/shiro-config.xml")
	方法2:自己通過shiro的Ini類加載ini配置文件。讀取自定義的urls。

步驟

自定義 authc 對應過濾器 FormAuthenticationFilter。覆蓋 onAccessDenied 方法返回JSON響應。

將自定義過濾器添加到 ShiroFilterFactoryBean。名稱為 authc 。

ResultFormAuthenticationFilter

package com.mozq.shiro.shiro01.config;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;

@Slf4j
public class ResultFormAuthenticationFilter extends FormAuthenticationFilter {

    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                if (log.isTraceEnabled()) {
                    log.trace("Login submission detected.  Attempting to execute login.");
                }
                return executeLogin(request, response);
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("Login page view.");
                }
                //allow them to see the login page ;)
                return true;
            }
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
                          "Authentication url [" + getLoginUrl() + "]");
            }
            if(isAjaxRequest(request)){
                saveRequest(request);
                writeResult(response);
                return false;
            }
            //saveRequestAndRedirectToLogin(request, response);
            return false;
        }
    }

    private boolean isAjaxRequest(ServletRequest request){
        return request instanceof  HttpServletRequest && "XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest)request).getHeader("X-Requested-With"));
    }

    private void writeResult(ServletResponse servletResponse){
        if(servletResponse instanceof HttpServletResponse){
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            HashMap<String, String> result = new HashMap<>();
            result.put("code", "401");
            result.put("message","未登錄");
            try {
                response.setHeader("Content-Type", "application/json;charset=UTF-8");
                response.getWriter().write(JSONObject.toJSONString(result));
                response.getWriter().flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.yuantiao.smartcardms.config.shiro;

import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;

import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: changzhou.xie@yuantiaokj.com
 * @date: 2019/11/1 14:14
 */
@Configuration
public class ShiroConfig {

    //自定義 org.apache.shiro.realm.Realm
    @Bean
    public Realm realm(){
        //IniRealm iniRealm = new IniRealm("classpath:user.ini");
        SysUserRealm realm = new SysUserRealm();
        return realm;
    }

    //定義 org.apache.shiro.mgt.SecurityManager
    @Bean
    public SecurityManager securityManager(Realm realm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        return securityManager;
    }

    //定義 org.apache.shiro.spring.web.ShiroFilterFactoryBean
/*    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //過濾的路徑
        Map<String, String> map = new HashMap<>();
        map.put("/**", "authc");
        map.put("/user/login/pc", "anon");//放行登錄相關接口
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        shiroFilterFactoryBean.setLoginUrl("/login.html");//登錄頁面
        return shiroFilterFactoryBean;
    }*/
}

使用配置文件來創建ShiroFilterFactoryBean

package com.yuantiao.smartcardms;

import org.apache.catalina.connector.Connector;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportResource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * SpringBoot項目啟動類
 */
@SpringBootApplication
@EnableScheduling/* 開啟定時任務 */
@MapperScan("com.yuantiao.smartcardms.dao.mapper")
@ImportResource("classpath:shiro/shiro-config.xml")
public class SmartcardMsApplication {

    public static void main(String[] args) {
        SpringApplication.run(SmartcardMsApplication.class, args);
    }

    /**
     * CORS跨域請求解決403
     * @return
     */
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }

    /**
     * 跨域請求COOKIES攜帶SessionId
     * @return
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }

    /**
     * 請求鏈接[]{}非法字符
     * @return
     */
    @Bean
    public TomcatServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.addConnectorCustomizers((Connector connector) -> {
            connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}");
            connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}");
        });
        return factory;
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="filterChainDefinitionMap" >
            <!-- 用props無法保證資源是按照順序加載到filterChainDefinitionMap的,會有問題 -->
            <!--<props>-->
                <!--<prop key="/user/add">anon</prop>-->
                <!--<prop key="/user/delete">roles[laoban]</prop>-->
                <!--<prop key="/user/login/pc">anon</prop>-->
                <!--<prop key="/user/logout">anon</prop>-->
                <!--<prop key="/**">authc</prop>-->
            <!--</props>-->
            <map>
                <entry key="/user/login/pc" value="anon"/>
                <entry key="/**" value="authc"/>
            </map>
        </property>
        <property name="loginUrl" value="/login.html"/>
        <property name="securityManager" ref="securityManager"/>
        <property name="filters">
            <map>
                <entry key="authc">
                    <bean class="com.yuantiao.smartcardms.config.shiro.ResultFormAuthenticationFilter"/>
                </entry>
            </map>
        </property>
    </bean>

</beans>

錯誤

<property name="filterChainDefinitionMap" >
    <value>
        /card.html = anon
        /** = authc
    </value>
</property>
<!--
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map' for property 'filterChainDefinitionMap': no matching editors or conversion strategy found

看到網上很多filterChainDefinitionMap這種寫,但是一配置直接報錯。value指定的是字符串,而filterChainDefinitionMap是一個LinkedHashMap對象。完全無法這樣配置。
-->

bugs

jquery-3.1.1.min.js:4 POST http://localhost:9000/smartcard/user/login/pc 415
請求頭:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Set-Cookie: JSESSIONID=080D2E469D78CD39C88AE54950B6640D; Path=/smartcard; HttpOnly
Set-Cookie: rememberMe=deleteMe; Path=/smartcard; Max-Age=0; Expires=Sat, 02-Nov-2019 02:32:54 GMT


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM