要解决ajax请求返回数据,问题很简单,比如你没有登录,去请求数据的时候,shiro指定了一个登录界面,会自动重定向那个界面,使用ajax请求的时候,需要返回数据为json格式这时候可以这么做:
编写一个接口:
@GetMapping("/401")
public ResultData notLogin(){
return ResultData.resultMsg(-104,"请先登录");
}
然后把登录url设置成这个,返回的就是json格式的数据了,但是问题来了,当你跨域请求的时候,会报错,即使你设置了全局跨域,ajax请求首先会发送一个option请求,测试该链接是否能用,再来请求数据,这个时候,会报错,说不允许重定向,于是需要再shiro过滤器中改造以下,重继承FormAuthenticationFilter类,重写preHandle,onAccessDenied方法
//判断是否是option请求,是就直接放行
@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,不进行重定向。
* @param request
* @param response
* @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
* @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,"请先登录")));
return false;
}
然后再权限配置中,使用自定义的过滤器
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: 权限配置
* @author: jiang wei
* @create: 2019-04-24 14:13
*/
//@Configuration
public class ShiroConfig {
/**
* 配置接口权限
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//shiroFilterFactoryBean.setLoginUrl("/admin-info/401");//设置登录界面
shiroFilterFactoryBean.setUnauthorizedUrl("/manager/login.html");//设置无权限界面
//设置自定义过滤器
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;
}
/**
* 注入权限管理
* @return
*/
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setRealm(customRealm());
return securityManager;
}
@Bean
public CustomRealm customRealm(){
return new CustomRealm();
}
}
这个时候,你请求数据,还会报错,说跨域问题,于是需要继续改造,继续再自定义过滤器中写跨域处理,贴过滤器完整代码
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,不进行重定向。
* @param request
* @param response
* @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
* @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,"请先登录")));
return false;
}
/**
* 为response设置header,实现跨域
*/
private void setHeader(HttpServletRequest request,HttpServletResponse response){
//跨域的header设置
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数据
//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("*")
//设置是否允许跨域传cookie
.allowCredentials(true)
//设置缓存时间,减少重复响应
.maxAge(3600);
}
};
}
}
问题解决,可以正常访问数据,而且未登录的时候是以json格式返回的,无权限设置json返回同理继承PermissionsAuthorizationFilter,实现方法和验证身份返回json一样,过滤器perms使用自定义过滤器。
但是最后还有一个问题,跨域的时候,ajax请求数据,是属于一次性的请求,还是无法验证身份,这时候需要回传token,服务器继承DefaultWebSecurityManager,重写里面的方法,来验证token是否可用以及鉴权,
这个问题,下一章再做讲解
网友评论