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

相关推荐
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~4 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616884 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
程序媛小果5 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
AskHarries7 小时前
Spring Boot集成Access DB实现数据导入和解析
java·spring boot·后端
2401_857622668 小时前
SpringBoot健身房管理:敏捷与自动化
spring boot·后端·自动化
程序员阿龙8 小时前
基于SpringBoot的医疗陪护系统设计与实现(源码+定制+开发)
java·spring boot·后端·医疗陪护管理平台·患者护理服务平台·医疗信息管理系统·患者陪护服务平台
前 方8 小时前
若依入门案例
java·spring boot·maven
阿华的代码王国8 小时前
【Spring】——SpringBoot项目创建
java·spring boot·后端·启动类·target文件