要解決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è)問題,下一章再做講解