“如何避开 shiro自定义拦截和WebMvcConfigurationSupport 过滤器的各种坑!!!!!”

场景:因开发需要,时间有限,便在某云上下载了一个开源框架-脚手架,
希望能便捷开发,提高开发效率
ps:框架是个好框架,大家也可以学习学习
springboot_v2
问题描述:因为这个框架本身采用shiro 做权限拦截,本身是属于一个web
管理后台框架,但是我这边需求是还需要对接手机接口,
但是,在框架中,针对未登录用户的拦截是返回login.html,
手机接口也是采用同样拦截,导致手机接口在未登录的情况下
,会返回一个login.html,无法解析,但是对于web这个是必须需要的

,第一想法:卧槽,这么简单个玩意儿,容我2分钟搞定,
。。。。。。。。。。半个小时过后-未果,各种百度,必应,google,
头都看晕了,(我一看文档就犯困。。。。) shiro拦截顺序永远都在
WebMvcConfigurationSupport 前面·因为我已经踩了坑,
我在做拦截的时候
,拦截到的url全是shiro已经拦截,并且重定向到login的路径···

       首先:先上代码 ShiroConfig    
package com.fc.test.shiro.config;

import com.fc.test.shiro.service.ExtendRolesAuthorizationFilter;
import com.fc.test.shiro.util.ShiroUtils;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fc.test.shiro.service.MyShiroRealm;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;

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


/**
 * 权限配置文件
 * @ClassName: ShiroConfiguration
 * @author fuce
 * @date 2018年8月25日
 *
 */
@Configuration
public class ShiroConfig {

	/**
	 * 这是shiro的大管家,相当于mybatis里的SqlSessionFactoryBean
	 * @param securityManager
	 * @return
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//		Map filtersMap = new LinkedHashMap();
//		//自定义拦截器
//		filtersMap.put("authc", new ShiroLoginFilter());
//		shiroFilterFactoryBean.setFilters(filtersMap);
		shiroFilterFactoryBean.setFilterChainDefinitionMap(ShiroFilterMapFactory.shiroFilterMap());
		//登录
		shiroFilterFactoryBean.setLoginUrl("/admin/login");
		//首页
		shiroFilterFactoryBean.setSuccessUrl("/admin/login");
		shiroFilterFactoryBean.setSuccessUrl("/admin/index");
//		//错误页面,认证不通过跳转
		shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");
//		//页面权限控制


		shiroFilterFactoryBean.setSecurityManager(securityManager);
		return shiroFilterFactoryBean;
	}

	/**
	 * web应用管理配置
	 * @param shiroRealm
	 * @param cacheManager
	 * @param manager
	 * @return
	 */
	@Bean
	public DefaultWebSecurityManager securityManager(Realm shiroRealm,CacheManager cacheManager,RememberMeManager manager) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setCacheManager(cacheManager);
		securityManager.setRememberMeManager(manager);//记住Cookie
		securityManager.setRealm(shiroRealm);
		securityManager.setSessionManager(sessionManager());
		return securityManager;
	}
	/**
	 * session过期控制
	 * @return
	 * @author fuce
	 * @Date 2019年11月2日 下午12:49:49
	 */
	@Bean
	public  DefaultWebSessionManager sessionManager() {
		DefaultWebSessionManager defaultWebSessionManager=new DefaultWebSessionManager();
		// 设置session过期时间3600s
		Long timeout=60L*1000*60;//毫秒级别
		defaultWebSessionManager.setGlobalSessionTimeout(timeout);
		return defaultWebSessionManager;
	}
	/**
	 * 加密算法
	 * @return
	 */
	@Bean
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		hashedCredentialsMatcher.setHashAlgorithmName("MD5");//采用MD5 进行加密
		hashedCredentialsMatcher.setHashIterations(1);//加密次数
		return hashedCredentialsMatcher;
	}

	/**
	 * 记住我的配置
	 * @return
	 */
	@Bean
	public RememberMeManager rememberMeManager() {
		Cookie cookie = new SimpleCookie("rememberMe");
        cookie.setHttpOnly(true);//通过js脚本将无法读取到cookie信息
        cookie.setMaxAge(60 * 60 * 24);//cookie保存一天
		CookieRememberMeManager manager=new CookieRememberMeManager();
		manager.setCookie(cookie);
		return manager;
	}
	/**
	 * 缓存配置
	 * @return
	 */
	@Bean
	public CacheManager cacheManager() {
		MemoryConstrainedCacheManager cacheManager=new MemoryConstrainedCacheManager();//使用内存缓存
		return cacheManager;
	}

	/**
	 * 配置realm,用于认证和授权
	 * @param hashedCredentialsMatcher
	 * @return
	 */
	@Bean
	public AuthorizingRealm shiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
		MyShiroRealm shiroRealm = new MyShiroRealm();
		//校验密码用到的算法
		shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
		return shiroRealm;
	}

	/**
	 * 启用shiro方言,这样能在页面上使用shiro标签
	 * @return
	 */
	@Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

	/**
     * 启用shiro注解
     *加入注解的使用,不加入这个注解不生效
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }


}

shiroFilterMap

package com.fc.test.shiro.config;

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

/**
 * @ClassName: ShiroFilterMapFactory
 * @author fuce
 * @date 2018年8月26日
 *
 */
public class ShiroFilterMapFactory {

/**
anon:例子/admins/**=anon 没有参数,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数

roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。

port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString

是你访问的url里的?后面的参数。

authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查

*/

	public static Map<String, String> shiroFilterMap() {

//		设置路径映射,注意这里要用LinkedHashMap 保证有序
		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		//对所有用户认证
		filterChainDefinitionMap.put("/user/loginByUser", "anon"); //用户登录
		filterChainDefinitionMap.put("/user/loginByPhone", "anon");//手机号登录
		filterChainDefinitionMap.put("/user/getPhoneCode", "anon");//获取手机验证码
		filterChainDefinitionMap.put("/user/registered", "anon");//注册
		filterChainDefinitionMap.put("/user/forgetPassword", "anon");//忘记密码
		//swagger放开过滤
		filterChainDefinitionMap.put("/swagger-ui.html", "anon");
		filterChainDefinitionMap.put("/webjars/**", "anon");
		filterChainDefinitionMap.put("/v2/**", "anon");
		filterChainDefinitionMap.put("/swagger-resources/**", "anon");

		filterChainDefinitionMap.put("/static/**", "anon");//静态文件
		filterChainDefinitionMap.put("/admin/login", "anon");//登录页面
		filterChainDefinitionMap.put("/admin/logout", "logout");//登出页面
		//放验证码
		filterChainDefinitionMap.put("/captcha/**", "anon");//验证码
		// 释放 druid 监控画面
		filterChainDefinitionMap.put("/druid/**", "anon");
		//释放websocket请求
		filterChainDefinitionMap.put("/websocket", "anon");
		//前端
		filterChainDefinitionMap.put("/", "anon");
		filterChainDefinitionMap.put("/index", "anon");//任务调度暂时放开

		filterChainDefinitionMap.put("/quartz/**", "anon");

		//
		//对所有页面进行认证
		filterChainDefinitionMap.put("/**","authc");
		return filterChainDefinitionMap;
	}
}

可以很清楚的看到

		shiroFilterFactoryBean.setLoginUrl("/admin/login");
		shiroFilterFactoryBean.setSuccessUrl("/admin/login");
		shiroFilterFactoryBean.setSuccessUrl("/admin/index");
		shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");

配置了验证不通过跳转页面,我们的login,请看代码

/**
	 * 请求到登陆界面
	 * @param request
	 * @return
	 */
	@ApiOperation(value="请求到登陆界面",notes="请求到登陆界面")
	@GetMapping("/login")
    public Object login(ModelMap modelMap ,ServletRequest request, ServletResponse response) throws IOException {
        try {
            if ((null != SecurityUtils.getSubject() && SecurityUtils.getSubject().isAuthenticated()) || SecurityUtils.getSubject().isRemembered()) {
            	return "redirect:/"+prefix+"/index";
            } else {
            	System.out.println("--进行登录验证..验证开始");

            	modelMap.put("RollVerification", V2Config.getRollVerification());
            	System.out.println("V2Config.getRollVerification()>>>"+V2Config.getRollVerification());
//				return AjaxResult.NotLogin("login");
                return "login";
            }
        } catch (Exception e) {
        		e.printStackTrace();
        }
        return "login";
    }

未验证通过的请求被指向了这个接口中,项目中采用的thymeleaf模板
导致我手机未登录接口或者seesion过期导致跳转到这个接口,返回html,但是这明显不适用手机接口
如图:返回的html,当然对于web这个是必需品
“如何避开 shiro自定义拦截和WebMvcConfigurationSupport 过滤器的各种坑!!!!!”_第1张图片
百思不得其解之后,便开始决定自定义一个拦截器 基于WebMvcConfigurationSupport
前提是得把手机接口,和web接口分开(装在不同得controller)
开工
1:自定义一个异常

package com.fc.test.common.exception.demo;

/**
 * 手机接口异常
* @ClassName: PhoneModeException
* @author lp
* @date 2019-12-24 15:45
*
 */
public class PhoneModeException extends RuntimeException
{
    private static final long serialVersionUID = 1L;

    public PhoneModeException()
    {
    }
}

针对上面异常返回的状态码 --这个是重点

package com.fc.test.common.exception;

import javax.servlet.http.HttpServletRequest;

import com.fc.test.common.exception.demo.PhoneModeException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import com.fc.test.common.domain.AjaxResult;
import com.fc.test.common.exception.demo.DemoModeException;
import com.fc.test.util.ServletUtils;

/**
 * 全局异常处理
 * @author fuce
 * @date: 2018年9月9日 下午10:52:55
 */
@RestControllerAdvice
public class GlobalExceptionResolver{
	private static Logger logger = LoggerFactory.getLogger(GlobalExceptionResolver.class);



	 /**
     * 权限校验失败 如果请求为ajax返回json,普通请求跳转页面
     */
    @ExceptionHandler(AuthorizationException.class)
    public Object handleAuthorizationException(HttpServletRequest request, AuthorizationException e)
    {
		//开发环境打印异常,正式环境请注销
    	logger.error(" 权限校验异常》》"+e.getMessage(), e);
        if (ServletUtils.isAjaxRequest(request))
        {
            return AjaxResult.error(e.getMessage());
        }
        else
        {
        	ModelAndView mv;
        	//shiro异常拦截
          if(e instanceof UnauthorizedException){
          	//未授权异常
              mv = new ModelAndView("/error/403");
              return mv;
          }else if(e instanceof UnauthenticatedException){
          	//未认证异常
              mv = new ModelAndView("/error/403");
              return mv;
          }
          else {
              mv = new ModelAndView();
              return mv;

          }
        }
    }




    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public AjaxResult validatedBindException(BindException e)
    {
    	logger.error("自定义验证异常", e);
        String message = e.getAllErrors().get(0).getDefaultMessage();
        return AjaxResult.error(message);
    }


    /**
     * 请求方式不支持
     */
    @ExceptionHandler({ HttpRequestMethodNotSupportedException.class })
    public AjaxResult handleException(HttpRequestMethodNotSupportedException e)
    {
    	logger.error("请求方式不支持异常:", e);
        return AjaxResult.error("不支持' " + e.getMethod() + "'请求");
    }




   
   

    /**
     * 手机接口拦截
     */
    @ExceptionHandler(PhoneModeException.class)
    public AjaxResult PhoneModeException(PhoneModeException e)
    {
        return AjaxResult.NotLogin("未登录,请重新登录");
    }

  }

2:拦截逻辑-web Controller与app Controller 区分
我们来复习一下我们要做什么:针对手机接口,未登录用户返回状态码,并不是html ok 继续····

package com.fc.test.common.interceptor;

import cn.hutool.core.util.StrUtil;
import com.fc.test.common.conf.V2Config;
import com.fc.test.common.exception.demo.DemoModeException;
import com.fc.test.common.exception.demo.PhoneModeException;
import com.fc.test.shiro.util.ShiroUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义拦截器
 * @author lp
 *
 */
public class PhoneInterceptor implements HandlerInterceptor {

	/*************手机拦截器start*************/
	/**需要被拦截的post请求url**/
	public static List<String> posturllist=new ArrayList<String>();
	/**需要被拦截的get请求url**/
	public static List<String> geturllist=new ArrayList<String>();

	/**
	 * 初始化静态块,避免多次创建调用
	 * 需要拦截的请求集合
	 */
	static {
		//用户消费接口
		posturllist.add("/api/CBuyDataController/add_phone");
		geturllist.add("/api/CBuyDataController/add_phone");
		posturllist.add("/api/CBuyDataController/listByUser_phone");
		geturllist.add("/api/CBuyDataController/listByUser_phone");
		//返回课程文件
		posturllist.add("/api/CCourseContentsController/cCourseContentsId_Phone");
		geturllist.add("/api/CCourseContentsController/cCourseContentsId_Phone");
		//目录列表
		posturllist.add("/api/CCourseContentsController/listCCourseContents_Phone");
		geturllist.add("/api/CCourseContentsController/listCCourseContents_Phone");
		//课程详情
		posturllist.add("/api/CCourseController/CCourseData_Phone");
		geturllist.add("/api/CCourseController/CCourseData_Phone");
		//课程列表
		posturllist.add("/api/CCourseController/listCCourse_Phone");
		geturllist.add("/api/CCourseController/listCCourse_Phone");
		//测评列表
		posturllist.add("/api/CEvaluationController/listCEvaluation_Phone");
		geturllist.add("/api/CEvaluationController/listCEvaluation_Phone");
		//测评题目
		posturllist.add("/api/CEvaluationController/topicList_Phone");
		geturllist.add("/api/CEvaluationController/topicList_Phone");
		//查询课程/文章/测评是否购买(场景:用户点开课程/文章/测评详情时候调用-未缴费,提示缴费)--手机
		posturllist.add("/api/CommonController/CheckIsPay_Phone");
		geturllist.add("/api/CommonController/CheckIsPay_Phone");
		//查询课程文章是否需要购买
		posturllist.add("/api/CommonController/CheckVip_Phone");
		geturllist.add("/api/CommonController/CheckVip_Phone");
		//字典详情接口
		posturllist.add("/api/CommonController/DictList");
		geturllist.add("/api/CommonController/DictList");
		//咨询首页
		posturllist.add("/api/CommonController/advisoryHome_Phone");
		geturllist.add("/api/CommonController/advisoryHome_Phone");
		//文章列表
		posturllist.add("/api/SysArticleController/listSysArticle_Phone");
		geturllist.add("/api/SysArticleController/listSysArticle_Phone");
		//文章详情
		posturllist.add("/api/SysArticleController/viewinfoPhone");
		geturllist.add("/api/SysArticleController/viewinfoPhone");
		//用户信息完善
		posturllist.add("/api/user/dataGreate");
		geturllist.add("/api/user/dataGreate");
		//忘记密码
		posturllist.add("/api/user/forgetPassword");
		geturllist.add("/api/user/forgetPassword");

//		posturllist.add("");
//		geturllist.add("");
//		posturllist.add("");
//		geturllist.add("");



	}
	@Override
	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)throws Exception {
		// System.out.println(">>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
	}

	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception {
		// System.out.println(">>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
		//String url2=request.getScheme()+"://"+ request.getServerName();
		//System.out.println("xxxxxxxxx==="+"http://localhost:8081/");
		//System.out.println(">>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
		//设置前端的全局 地址,如果前端网页错乱请修改这儿
		request.setAttribute("rootPath", request.getContextPath());
		Boolean b = ifurl(request, response);
		if(b) {
			throw new PhoneModeException();
		}
		return true;// 只有返回true才会继续向下执行,返回false取消当前请求
	}

	/**
	 * 所有接口都拦截未登录状态码
	 * @param request
	 * @param response
	 * @return
	 * @author lp
	 * @Date 2019年12月24日 下午5:17:30
	 */
	public Boolean ifurl(HttpServletRequest request, HttpServletResponse response) {
		//当前请求
		String requesturl=request.getRequestURI();
		request.isRequestedSessionIdFromURL();
		if(request.getMethod().equals("POST")) {
			for (String postrul : posturllist) {
				if(StrUtil.containsAnyIgnoreCase(requesturl, postrul)) {
					if(ShiroUtils.getUser() ==null){
						return true;
					}else{
						return false;
					}
				}
			}
		}else {
			for (String geturl : geturllist) {
				if(StrUtil.containsAnyIgnoreCase(requesturl, geturl)) {
					if(ShiroUtils.getUser() ==null){
						return true;
					}else{
						return false;
					}
				}
			}
		}
		return false;
	}
}

上面代码中,定义出了所有手机接口包括POST/GET请求,并且获取当前登录用户,为空?那就是我们想要的东西了

3创建WebMvcConfigurationSupport 过滤器
package com.fc.test.common.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;


@Configuration
public class MyWebAppConfigurer  extends  WebMvcConfigurationSupport  {

	/** 解决跨域问题 **/
	@Override
	public void addCorsMappings(CorsRegistry registry){
		/*
			registry.addMapping("/**")
			// 设置允许跨域请求的域名
			.allowedOrigins("*")
			// 是否允许证书
			.allowCredentials(true)
			// 设置允许的方法
			.allowedMethods("GET", "POST", "DELETE", "PUT")
			// 设置允许的header属性
			.allowedHeaders("*")
			// 跨域允许时间
			.maxAge(3600);
			super.addCorsMappings(registry);
		*/
	}

	/** 添加拦截器 **/
	@Override
	protected void addInterceptors(InterceptorRegistry registry){
		registry.addInterceptor(new PhoneInterceptor());
		super.addInterceptors(registry);
	}

	/** 这里配置视图解析器 **/
	@Override
	protected void configureViewResolvers(ViewResolverRegistry registry){
		super.configureViewResolvers(registry);
	}

	/** 配置内容裁决的一些选项 **/
	@Override
	protected void configureContentNegotiation(ContentNegotiationConfigurer configurer){
		super.configureContentNegotiation(configurer);
	}

	/** 视图跳转控制器 **/
	@Override
	protected void addViewControllers(ViewControllerRegistry registry) {

		super.addViewControllers(registry);
	}


	/** 静态资源处理 **/
	@Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");

    }
	/** 默认静态资源处理器 **/

	protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		//super.configureDefaultServletHandling(configurer);
		//configurer.enable("stati");
		configurer.enable();
	}




}

其实只需要注意这段代码

/** 添加拦截器 **/
	@Override
	protected void addInterceptors(InterceptorRegistry registry){
		registry.addInterceptor(new PhoneInterceptor());
		super.addInterceptors(registry);
	}

我们把刚才我定义那个拦截url的方法添加到了拦截器
4:接下来我们取处理shiro拦截机制

package com.fc.test.shiro.config;

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

/**
 * @ClassName: ShiroFilterMapFactory
 * @author fuce
 * @date 2018年8月26日
 *
 */
public class ShiroFilterMapFactory {

/**
anon:例子/admins/**=anon 没有参数,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数

roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。

port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString

是你访问的url里的?后面的参数。

authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查

*/

	public static Map<String, String> shiroFilterMap() {

//		设置路径映射,注意这里要用LinkedHashMap 保证有序
		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		filterChainDefinitionMap.put("/Apis/**/**", "anon");
		//对所有用户认证
		filterChainDefinitionMap.put("/user/loginByUser", "anon"); //用户登录
		filterChainDefinitionMap.put("/user/loginByPhone", "anon");//手机号登录
		filterChainDefinitionMap.put("/user/getPhoneCode", "anon");//获取手机验证码
		filterChainDefinitionMap.put("/user/registered", "anon");//注册
		filterChainDefinitionMap.put("/user/forgetPassword", "anon");//忘记密码
		//swagger放开过滤
		filterChainDefinitionMap.put("/swagger-ui.html", "anon");
		filterChainDefinitionMap.put("/webjars/**", "anon");
		filterChainDefinitionMap.put("/v2/**", "anon");
		filterChainDefinitionMap.put("/swagger-resources/**", "anon");

		filterChainDefinitionMap.put("/static/**", "anon");//静态文件
		filterChainDefinitionMap.put("/admin/login", "anon");//登录页面
		filterChainDefinitionMap.put("/admin/logout", "logout");//登出页面
		//放验证码
		filterChainDefinitionMap.put("/captcha/**", "anon");//验证码
		// 释放 druid 监控画面
		filterChainDefinitionMap.put("/druid/**", "anon");
		//释放websocket请求
		filterChainDefinitionMap.put("/websocket", "anon");
		//前端
		filterChainDefinitionMap.put("/", "anon");
		filterChainDefinitionMap.put("/index", "anon");//任务调度暂时放开

		filterChainDefinitionMap.put("/quartz/**", "anon");

		//
		//对所有页面进行认证
		filterChainDefinitionMap.put("/**","authc");
		return filterChainDefinitionMap;
	}
}

其实只需要看到这段代码,我们对这个路径的拦截放开了??

filterChainDefinitionMap.put("/Apis/**/**", "anon");

好了 现在我只需要取解释这个是是干啥的呢
上图:“如何避开 shiro自定义拦截和WebMvcConfigurationSupport 过滤器的各种坑!!!!!”_第2张图片我这里有两个contorller明显我们放开的对apicontroller的拦截,为啥放开呢?因为我们要使用我自定义的拦截取处理这些请求,而apicontroller里我全装了手机接口,并且添加了前缀
“如何避开 shiro自定义拦截和WebMvcConfigurationSupport 过滤器的各种坑!!!!!”_第3张图片
好了 现在我们在重启项目,在不登陆的时候直接访问swagger 地址,模拟手机未登录请求/session获取导致返回login.html的场景
“如何避开 shiro自定义拦截和WebMvcConfigurationSupport 过滤器的各种坑!!!!!”_第4张图片
surprise!!!!!!
再模拟一下网页未登录访问页面,首先我们登录一个网页
“如何避开 shiro自定义拦截和WebMvcConfigurationSupport 过滤器的各种坑!!!!!”_第5张图片
然后另外开一个窗口,复制网址
再另外一个窗口中点击退出登录
然后回来当前窗口随机点击菜单
“如何避开 shiro自定义拦截和WebMvcConfigurationSupport 过滤器的各种坑!!!!!”_第6张图片
对于web 请求直接退回了登录页面login.html
完美解决

当然这是一个前后不分离的框架,同时还对接了手机接口,没办法我这小公司,条件不允许,前后台都是我做,我一个老实巴交的后台真不会前端,索性选了一个自己会点儿的框架,条件允许,并且前后分离的框架完全没有这些困扰
也有一个问题 ----就是我菜啊······哈哈··

你可能感兴趣的:(java)