SpringBoot拦截器获取token用户对象优雅地传递到Controller层

项目场景:

SpringBoot拦截器获取token用户对象优雅地传递到Controller层


问题描述

后端有许多接口都需要请求中携带有正确的Token,这时采用拦截器来验证token,但是每个接口都还是需要解析一遍token,浪费资源,不免显得代码繁琐,臃肿。``


解决方案:

我们可以把用户信息存储起来,方便其它地方获取,两种方式:

  1. 使用ThreadLocal线程存储(推荐)
  2. 存储到上下文中request.setAttribute

1、自定义拦截器Interceptor

抛出的异常需要自己捕捉,返回

java 复制代码
package com.test.aop;

import com.test.entity.TokenUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Token拦截器
 */
@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {

    /**
     * 存储用户信息
     */
    private static ThreadLocal<TokenUserInfo> userThread = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

		// 从header中获取token
		String token = request.getHeader(CommonConstant.ACCESS_TOKEN);

		// 如果参数中不存在token,则报错
		if (StringUtils.isBlank(token)) {
			throw new RuntimeException("请求头缺少token参数");
		}

		try {
            // TODO 根据token获取用户信息
            // ......
        }catch (Exception e){
            log.error("获取用户信息失败:", e);
            throw new RuntimeException("获取用户信息失败");
        }


        //模拟已经获取到了用户信息
        TokenUserInfo tokenUserInfo = new TokenUserInfo();
        tokenUserInfo.setUserId("1227086153ef415896da5819d4fb4c2f");
        tokenUserInfo.setLoginAccount("test");
        tokenUserInfo.setLoginUserName("测试");

        //token失效
        if(tokenUserInfo == null){
            throw new RuntimeException("token失效");
        }

        /*
         * 存储用户信息方便其它地方获取,两种方式
         * 1.使用ThreadLocal线程存储(推荐)
         * 2.存储到上下文中request.setAttribute
         */

        // 放入线程域
        userThread.set(tokenUserInfo);

        //2.存储到上下文中request.setAttribute
//        request.setAttribute("tokenUserInfo",tokenUserInfo);

        //放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //程序运行结束之后,删除线程,防止内存泄漏
        userThread.remove();
    }

    public static TokenUserInfo getUser() {
        return userThread.get();
    }

}

用户实体类

java 复制代码
package com.test.entity;

import lombok.Data;

/**
 * 用户信息
 *
 */
@Data
public class TokenUserInfo {

    /**
     * 用户id
     */
    private String userId;
    /**
     * 登录帐号
     */
    private String loginAccount;
    /**
     * 用户名
     */
    private String loginUserName;
}

2、配置拦截器

java 复制代码
package com.test.config;

import com.test.aop.TokenInterceptor;
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.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * WebMvc配置
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
	/**
	 * 解决跨域问题
	 */
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**").allowedOrigins("*").allowCredentials(true)
				.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").maxAge(3600);
	}
	
	@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        registry.addResourceHandler("/swagger/**").addResourceLocations("classpath:/static/swagger/");
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
    }

	@Resource
	private TokenInterceptor tokenInterceptor;

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//不拦截的地址
		List<String> excludedList = new ArrayList<>();
		//swagger地址
		excludedList.add("/swagger-ui.html");
		excludedList.add("/swagger-ui.html/**");
		excludedList.add("/webjars/**");
		excludedList.add("/swagger/**");
		excludedList.add("/doc.html");
		excludedList.add("/doc.html/**");
		excludedList.add("/swagger-resources/**");
		excludedList.add("/v2/**");
		excludedList.add("/favicon.ico");


		registry.addInterceptor(tokenInterceptor)
				.addPathPatterns("/**")//拦截所有请求
				.excludePathPatterns(excludedList);//排除的请求
		super.addInterceptors(registry);
	}
}

3、Controller层获取

java 复制代码
package com.test.controller;

import com.test.aop.TokenInterceptor;
import com.test.entity.TokenUserInfo;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@RestController
@Api(tags = "测试接口")
@RequestMapping("/test")
public class TestController {

	@RequestMapping(value = "/get", method = RequestMethod.GET)
	public String get(HttpServletRequest request) {
		/*
		 * 优雅的获取用户信息,两种方式
		 * 1.使用ThreadLocal线程存储(推荐)
		 * 2.存储到上下文中request.setAttribute
		 */

		TokenUserInfo tokenUserInfo = TokenInterceptor.getUser();
//		TokenUserInfo tokenUserInfo = (TokenUserInfo) request.getAttribute(CommonConstant.USER_INFO);

		return "success";
	}
}

参考源码:https://download.csdn.net/download/u011974797/85849196

相关推荐
战族狼魂3 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
用键盘当武器的秋刀鱼6 小时前
springBoot统一响应类型3.5.1版本
java·spring boot·后端
小李同学_LHY7 小时前
三.微服务架构中的精妙设计:服务注册/服务发现-Eureka
java·spring boot·spring·springcloud
爱喝醋的雷达8 小时前
Spring SpringBoot 细节总结
java·spring boot·spring
嘵奇10 小时前
深入解析 Spring Boot 测试核心注解
java·spring boot·后端
技术liul12 小时前
解决Spring Boot Configuration Annotation Processor not configured
java·spring boot·后端
腥臭腐朽的日子熠熠生辉14 小时前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
绝顶少年16 小时前
Spring Boot 注解:深度解析与应用场景
java·spring boot·后端
西木风落17 小时前
springboot整合Thymeleaf web开发出现Whitelabel Error Page
spring boot·thymeleaf error·whitelabelerror
有来技术18 小时前
从0到1手撸企业级权限系统:基于 youlai-boot(开源) + Java17 + Spring Boot 3 完整实战
java·spring boot·后端