过滤器和拦截器的实际应用——实现token认证

一、过滤器filter

1.登录的时候后台根据用户ID和用户名生成一个带有时效的token

2.前端获取道token,写入cookies

3.前端请求的时候带上token

4.后端解析token,token为空,或者失效视为认证失败!

5.前端统一封装请求,如果是认证失败的,跳回登录页面

涉及工具、方法:

(1)过滤器Filter实现拦截

(2)过滤器注册到spring容器

(3)jjwt实现token生成和解析

(4)/login的地址不拦截

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xy.service</groupId>
    <artifactId>my-springboot-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>my-springboot-service</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <!--<scope>runtime</scope>-->
            <!--<optional>true</optional>-->
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

        <!--json-->
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.3</version>
            <classifier>jdk15</classifier>
        </dependency>
        <!--jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork><!-- 如果没有该配置,热部署的devtools不生效 -->
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

RestfulRequestFilter.java 过滤器

package com.app.service.filter;


import com.app.service.constant.CommonConstant;
import com.app.service.utils.resp.ResponseUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import net.sf.json.JSONObject;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RestfulRequestFilter implements Filter {
    private static final long serialVersionUID = 1L;

    public RestfulRequestFilter() {
    }

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS,PUT");
        response.setHeader("Access-Control-Max-Age", "0");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
        response.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
        if (request.getMethod().equals("OPTIONS")) {
            response.setStatus(200);
        } else {
            String url = request.getRequestURL().toString();
            String urlParams = request.getQueryString();
            String contnetType = request.getContentType();
            if (this.ifNotNeedCheck(url)) {
                chain.doFilter(req, res);
            } else {
                int resultCd = this.checkAccess(request, response);
                String result = "";
                switch(resultCd) {
                    case 0:
                        chain.doFilter(req, res);
                        return;
                    case 1:
                        result = ResponseUtils.error(401,"认证失败!");
                        break;
                    default:
                        result = ResponseUtils.error(401,"认证失败!");

                }

                response.getOutputStream().write(result.getBytes("UTF-8"));
                response.setContentType("text/json; charset=UTF-8");
            }
        }
    }

    private boolean ifNotNeedCheck(String url) {
        String[] acceptUrls = new String[]{"/login"};

        for(int i = 0; i < acceptUrls.length; ++i) {
            if (url.indexOf(acceptUrls[i]) > -1) {
                return true;
            }
        }

        return false;
    }

    private int checkAccess(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null) {
            return 1;
        } else {
            String token = authHeader;
            try {
                JSONObject staffInfoJo = parseToken(token);
                request.setAttribute("userId", staffInfoJo.getString("userId"));
                request.setAttribute("Authorization", authHeader);
                return 0;
            } catch (Exception var6) {
                return 2;
            }
        }
    }
    /**
     * 解析token
     * @param token
     * @return
     */
    public static JSONObject parseToken(String token){
        JSONObject staffInfoJo = null;
        try {
            final Claims claims = Jwts.parser().setSigningKey(CommonConstant.SECRET_KEY).
                    parseClaimsJws(token).getBody();
            staffInfoJo = JSONObject.fromObject(claims.getSubject());
        } catch (Exception e) {
            final Claims claims = Jwts.parser().setSigningKey("secretkey")
                    .parseClaimsJws(token).getBody();
            staffInfoJo = JSONObject.fromObject(claims.getSubject());
        }
        return staffInfoJo;
    }
    public static void main(String[] args) {
        JSONObject staffInfojo = new JSONObject();
        staffInfojo.put("userId", "1001");
        staffInfojo.put("userName", "jack");
//        String token = Jwts.builder().setSubject(staffInfojo.toString()).claim("pwd", "hahaha,if you think this is pwd,then you are wrong").setIssuedAt(new Date()).signWith(SignatureAlgorithm.HS256, "10000_YEARS_PPM").setExpiration(new Date(System.currentTimeMillis() + 2592000000L)).compact();
//        LOG.debug(token);
    }
}

FilterConfig.java 加入spring容器

package com.app.service.config;

import com.app.service.filter.RestfulRequestFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new RestfulRequestFilter());
        bean.addUrlPatterns("/*");
        return bean;
    }
}

controller 生成token

String token = JWTUtil.genToken(jsonObject); 
Map<String, Object> result = new HashMap<>(); 
result.put("token", token) ResponseUtils.success(result);

token工具类

package com.app.service.utils;

import com.app.service.constant.CommonConstant;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.Map;

/**
 * JWT 工具类
 * JSON Web Token (JWT)是一种基于 token 的认证方案
 * 简单的说,JWT就是一种Token的编码算法,服务器端负责根据一个密码和算法生成Token,然后发给客户端,客户端只负责后面每次请求都在HTTP header里面带上这个Token,服务器负责验证这个Token是不是合法的,有没有过期等,并可以解析出subject和claim里面的数据。
 注意:JWT里面的数据是BASE64编码的,没有加密,因此不要放如敏感数据
 
 *
 */
public class JWTUtil {
   
   /**
    * 生成token
    * @param obj
    * @return
    */
   public static String genToken(Object obj){
      String token = Jwts.builder()
      .setSubject(obj.toString()) // 账号
      .claim("pwd", "I'm password")
      .setIssuedAt(new Date())
      .signWith(SignatureAlgorithm.HS256, CommonConstant.SECRET_KEY)
      .setExpiration(new Date(System.currentTimeMillis() + 15*1000L)) // token有效期:1天
      .compact();
//    1天  3600*24*1000L
//    1分钟 60*1000L
//    15秒 15*1000L
      return token;
   }
   public static String getExpireToken() throws Exception {
      String expireToken = Jwts.builder()
            .setSubject("exipre account") // 账号
            .claim("pwd", "I'm password")
            .setIssuedAt(new Date())
            .signWith(SignatureAlgorithm.HS256,CommonConstant.SECRET_KEY)
            .setExpiration(new Date(System.currentTimeMillis() - 5000L)) // 直接失效
            .compact();

      return expireToken;
   }
	public static void main(String[] args) {
		JSONObject staffInfojo = new JSONObject();
		staffInfojo.put("userId", "1001");
		staffInfojo.put("userName", "jack");
//生成一个token,用来测试
		System.out.println(genToken(staffInfojo));
	}
}

controller

package com.xy.service.controller;

import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class TestController {
    @RequestMapping(value = "/hello", produces = "application/json; charset=UTF-8", method = RequestMethod.POST)
//    @AuthIgnore
    public Map<String,Object> queryCustomerList(@RequestHeader("token") String token) {
        Map<String, Object> result = new HashMap<>();
        result.put("code","200");
        result.put("msg","成功");
        return result;
    }
}

用 JWTUtil跑出来的测试token,放到header里面,运行

 运行成功:

 没有传token呢,或者是过期的token就会认证失败

二、拦截器

JWTInterceptor
package com.xy.service.config;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.xy.service.constant.CommonConstant;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class JWTInterceptor extends HandlerInterceptorAdapter  {


    public static JSONObject parseToken(String token){
        JSONObject staffInfoJo = null;
        try {
            final Claims claims = Jwts.parser().setSigningKey(CommonConstant.SECRET_KEY).
                    parseClaimsJws(token).getBody();
            staffInfoJo = JSONObject.fromObject(claims.getSubject());
        } catch (Exception e) {
            final Claims claims = Jwts.parser().setSigningKey("secretkey")
                    .parseClaimsJws(token).getBody();
            staffInfoJo = JSONObject.fromObject(claims.getSubject());
        }
        return staffInfoJo;
    }
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        log.debug("{}",request.getRequestURL());
        if(!(handler instanceof HandlerMethod)) {
            return true;
        }
        AuthIgnore annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthIgnore.class);

        if (annotation != null && !annotation.required()) {
            return true;
        }
        Map<Object, Object> map = new HashMap<>();
        String authHeader = request.getHeader("token");
        if (authHeader == null) {
            map.put("msg","token无效!");
        } else {
            String token = authHeader;
            try {
                JSONObject staffInfoJo = parseToken(token);
                request.setAttribute("userId", staffInfoJo.getString("userId"));
                request.setAttribute("Authorization", authHeader);
                map.put("state",true);
                map.put("msg","请求成功");
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                map.put("msg","token无效!");
            }
        }
        //将 map装换为json ResponseBody底层使用jackson
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}
GlobalWebMvcConfig
package com.xy.service.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Slf4j
@Configuration
public class GlobalWebMvcConfig implements WebMvcConfigurer {

    /**
     * 重写父类提供的跨域请求处理的接口
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 添加映射路径
 /*       registry.addMapping("/**")
                // 放行哪些原始域
//                .allowedOrigins("*")
                // 是否发送Cookie信息
                .allowCredentials(true)
                // 放行哪些原始域(请求方式)
                .allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS", "HEAD")
                // 放行哪些原始域(头部信息)
                .allowedHeaders("*")
                // 暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                .exposedHeaders("Server","Content-Length", "Authorization", "Access-Token", "Access-Control-Allow-Origin","Access-Control-Allow-Credentials");
   */
    }


    /**
     * 添加拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加权限拦截器
        registry.addInterceptor(new JWTInterceptor()).addPathPatterns("/**");
    }

}

运行,同样的进行token认证

 

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 可以通过实现 Filter 接口来创建一个过滤器,然后在 Spring Boot 中使用 @Bean 注解将其注册到应用程序中。在过滤器中,可以通过 HttpServletRequest 对象获取请求头中的 token,然后进行验证或者其他操作。具体实现可以参考 Spring Boot 官方文档或者相关教程。 ### 回答2: 在使用Spring Boot中,可以通过创建一个过滤器拦截token。下面是一个简单的示例,说明如何实现。 首先,需要创建一个自定义的过滤器类,实现javax.servlet.Filter接口。在实现过滤器时,我们可以在doFilter方法中进行token验证的逻辑处理。以下是示例代码: ```java import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class TokenFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 将请求和响应对象转换成HttpServletRequest和HttpServletResponse对象 HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; // 从请求头中获取token String token = httpRequest.getHeader("Authorization"); // 进行token验证的逻辑处理,例如验证token是否过期、是否有效等 // ... // 如果验证通过,将请求继续传递给下一个过滤器或目标资源处理 chain.doFilter(request, response); } // 其他方法,例如init和destroy方法,可以留空不做处理 } ``` 接下来,需要将自定义的过滤器添加到Spring Boot应用程序中。可以使用@Configuration注解将过滤器添加为一个Bean,并使用@Order注解指定过滤器的执行顺序。例如: ```java import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<TokenFilter> tokenFilter() { FilterRegistrationBean<TokenFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new TokenFilter()); // 设置过滤器的URL映射规则,例如/*表示拦截所有请求 registrationBean.addUrlPatterns("/*"); // 设置过滤器的执行顺序 registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); return registrationBean; } } ``` 最后,重新启动Spring Boot应用程序,自定义的过滤器就会拦截所有请求,并对token进行验证处理。 请注意,上述示例只是一个简单的演示,实际应用中可能需要根据具体的需求进行修改和扩展。例如,可以从数据库或缓存中获取token,进行更加复杂的验证逻辑,并在验证失败时返回相应的错误信息。 ### 回答3: 使用Spring Boot实现过滤器拦截Token的步骤如下: 1. 创建一个自定义的过滤器类,实现javax.servlet.Filter接口,并重写doFilter方法。在doFilter方法中,可以通过HttpServletRequest对象获取请求头中的Token信息,并进行相应的验证或处理。 2. 在Spring Boot应用的启动类中,通过添加注解@EnableWebSecurity开启Web安全配置,并通过继承WebSecurityConfigurerAdapter类重写configure方法。 3. 在configure方法中,使用http对象的addFilterBefore方法将自定义的过滤器添加到过滤器链中,指定过滤器在哪个过滤器之前进行拦截。 4. 在过滤器中,可以进行Token的验证和处理逻辑。例如,可以使用JWT来生成和验证Token,或将Token存储在Redis中,根据请求的Token进行校验等。 5. 如果Token验证不通过,可以返回相应的错误信息或重定向到登录页面。如果验证通过,可以进行其他的业务逻辑处理。 总之,通过自定义过滤器并将其添加到Spring Boot的过滤器链中,可以在请求到达Controller之前进行Token的验证和拦截操作,以实现对请求的安全控制。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值