jwt权限验证2

风格不统一 提交于 2020-08-13 19:54:51

1.生成token值

@RequestMapping(value = "login",method = RequestMethod.GET)
public BasePageData login(@RequestParam(value = "username",required =true)String username,
						  @RequestParam(value = "password",required =true)String password){
	BasePageData data = new BasePageData();
	//判断用户名和密码是否正确
	User user = userService.getUserLoginPass(username,password);
	if(null!=user){
		//判断用户名是否正确
		Map<String, Object> claims = new HashMap<>();
		String token = JwtUtils.createJWT(user.getId().toString(),user.getUname(),JwtUtils.EXPIRATION_TIMEMILLIS,claims);
		data.setCode(WebResponseCode.APPSUCCESS);
		data.setMsg("登录成功!");
		data.setData(token);
	}else {
		data.setCode(WebResponseCode.APPFAIL);
		data.setMsg("用户名或者密码错误!");
		data.setData(null);
	}
	return data;
}

2.定义拦截器

/**
 * 自定义拦截器 ,作用不用再在每个方法前都去解析token了
 * .在preHandle中,可以进行编码、安全控制等处理;进入到api接口之前要做的事 必须要有布尔类型的返回值
 * true 表示可以继续执行
 * false 拦截了表示 不能往下执行了
 * 2.在postHandle中,有机会修改ModelAndView; 执行api方法之后要干的事
 * 3.在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。 所有的请求结束之后要做的事
 */
@Component
public class JwtInterceptor extends HandlerInterceptorAdapter {
    public JwtInterceptor() {
        super();
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /**
         * 简化获取token 数据的代码编写, 统一用户的权限校验 即是否登录 ,也可以判断当前用户是否有当前访问接口的权限
         */
        //表示该用户没有登录,输出 出错信息
        ServletOutputStream out = response.getOutputStream();
        try {
            response.setHeader("Content-type", "text/html;charset=UTF-8");
            BasePageData basePageData = new BasePageData();
            //1.通过request 获取token
            String authorization = request.getHeader("token");
            //spring 判断为空的方法
            if (!StringUtils.isEmpty(authorization)) {
                //表示该用户登录
                //获取到token 信息
                basePageData = JwtUtils.validateJWT(authorization);
                if (basePageData.getCode() == 1) {
                    return true;
                }else {
                    out.write(JsonUtils.toJson(basePageData).getBytes("UTF-8"));
                    return false;
                }
            } else {
                basePageData.setCode(WebResponseCode.APPFAIL);
                basePageData.setMsg("token参数不能为空");
                basePageData.setData(null);
                out.write(JsonUtils.toJson(basePageData).getBytes("UTF-8"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        super.afterCompletion(request, response, handler, ex);
    }
}

3.配置拦截器

/**
 * 拦截器配置
 */
@Configuration
public class SystemConfig extends WebMvcConfigurationSupport {
    //注入自定义的 拦截器
    @Autowired
    private JwtInterceptor jwtInterceptor;

    /**
     * 添加拦截器配置
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        //添加自定义拦截器
        registry.addInterceptor(jwtInterceptor).addPathPatterns("/**") //指定拦截的url地址
                .excludePathPatterns("/login");//指定不拦截的url地址
    }
	    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        //重写这个方法,映射静态资源文件
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/resources/")
                .addResourceLocations("classpath:/static/")
                .addResourceLocations("classpath:/public/");
        super.addResourceHandlers(registry);
    }
}

4.配置跨域

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true) .maxAge(3600)  .allowedHeaders("*");
    }
}

5.配置过滤器

/**
 * describe:在过滤器中设置响应头
 */
@WebFilter(filterName = "CorsFilter")
@Configuration
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, response);
    }

    @Override
    public void init(FilterConfig filterConfig) {}

    @Override
    public void destroy() {}

}

6.异常


  1. String Boot 异常 HttpMediaTypeNotAcceptableException 的原因和处理
客户端和服务器端请求返回类型不一致造成的
解决方法:
	客户端(前端)的解决
	在请求头添加多种媒体类型,用逗号分割
	Accept: application/json, text/plain 
	又或者直接用*号匹配所有类型
	Accept: */*
  1. Springboot 拦截器 异常:IllegalStateException: getWriter() has already been called for this response
错误信息:是一个响应多次调用了getWriter(),更改为流
 ServletOutputStream out = response.getOutputStream(); 
 out.write(JsonUtils.toJson(validateMsg).getBytes("utf-8"));
  1. java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
	这个是要把关闭流去掉out.close();就可以了 
  1. org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
	客户端 和 服务器 的请求头指定了期望响应的媒体类型不一致造成的
	客户端(前端)的解决:
		在请求头添加多种媒体类型,用逗号分割
			Accept: application/json, text/plain  或者  Accept: */*
	服务端处理:
		方式一:删掉produces属性: @RequestMapping(value="test",produces="text/plain")
		方式二:修改produces为Accept期望的类型@RequestMapping(value=“test”,produces=“application/json”)
  1. apiDoc: Problem: return "error 0 undefined" in Spring Boot
	跨域问题导致, 可在spring boot 中方法前面加上注解:
	@CrossOrigin

JAVA过滤器和拦截器的区别

什么是拦截器

在AOP中用于在某个方法或字段被访问之前,进行拦截然后再之前货之后加入某些操作。拦截是AOP的一种实现策略。 拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者定义一个action前后执行的代码,也可以在一个action执行阻止其执行,同时也是提供了一种可以提取action可重用部分的方式。 实现原理:大部分是通过代理的方式来调用的。 自定义拦截器步骤: 自定义一个实现了Interceptor接口的类,或者继承抽象类AbstractInterceptor。 在配置文件中注册定义的拦截器。 在需要使用Action中引入定义的拦截器,为了方便也可以把拦截器定义为默认的拦截器。所有的Action都会被这个拦截器拦截

什么是过滤器

过滤器是一个程序,他先于与之相关的servlet或jsp也可以运行在服务器上。过滤器可附加到一个或多个servlet或jsp页面上,并且可以检查进入这些资源的请求信息。 以常规的方式调用资源 利用修改过的请求信息调用资源 调用资源,但在发送响应到客户机前对其进行修改 阻止该资源调用,代之以转到其他的资源,返回一个特定的状态代码或生成替换输出。 过滤器的基本原理:在Servlet作为过滤器使用时,他可以对客户的请求进行处理。处理完成后,他会交给下一个过滤器处理,这样,客户的请求在过滤器链中逐个处理,直到请求发送到目标为止。

拦截器与过滤器的区别

拦截器是基于java的反射机制的,而过滤器是基本函数回调。 拦截器不依赖于servlet容器,过滤器依赖于servlet容器 拦截器只能对action请求起作用,过滤器可以对几乎所有的请求起作用 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问 在action的生命周期中,拦截器可以被多次调用,而过滤器只能在容器初始化时被调用过一次。

  1. 过滤器(Filter):所谓过滤器顾名思义是用来过滤的,Java的过滤器能够为我们提供系统级别的过滤,也就是说,能过滤所有的web请求,这一点,是拦截器无法做到的。在Java Web中,你传入request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者struts的action前统一设置字符集,或者去除掉一些非法字符(聊天室经常用到的,一些骂人的话)。filter 流程是线性的,url传来之后,检查之后,可保持原来的流程继续向下执行,被下一个filter, servlet接收。
  2. 监听器(Listener):Java的监听器,也是系统级别的监听。监听器随web应用的启动而启动。Java的监听器在c/s模式里面经常用到,它会对特定的事件产生产生一个处理。监听在很多模式下用到,比如说观察者模式,就是一个使用监听器来实现的,在比如统计网站的在线人数。又比如struts2可以用监听来启动。Servlet监听器用于监听一些重要事件的发生,监听器对象可以在事情发生前、发生后可以做一些必要的处理。
  3. 拦截器(Interceptor):java里的拦截器提供的是非系统级别的拦截,也就是说,就覆盖面来说,拦截器不如过滤器强大,但是更有针对性。Java中的拦截器是基于Java反射机制实现的,更准确的划分,应该是基于JDK实现的动态代理。它依赖于具体的接口,在运行期间动态生成字节码。拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或者之后加入某些操作。java的拦截器主要是用在插件上,扩展件上比如 Hibernate Spring Struts2等,有点类似面向切片的技术,在用之前先要在配置文件即xml,文件里声明一段的那个东西。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!