背景

我们有一个Web项目,这个项目提供了很多的Rest API。也做了权限控制,访问API的请求必须要带上事先认证后获取的Token才可以。

认证的话就在Filter中进行的,会获取请求的Token进行验证,如果成功了可以得到Token中的用户信息,本文的核心就是讲解如何将用户信息(用户ID)优雅的传递给API接口(Controller)。

方式一(很挫)

我们在Filter中进行了统一拦截,在Controller中获取用户ID的话,仍然可以再次解析一遍Token获取用户ID

@GetMapping("/hello")
public String test(HttpServletRequest request) {
String token = request.getHeader("token");
JWTResult result = JWTUtils.checkToken(token);
Long userId = result.getUserId();
}

方式二(优雅)

方式一需要重新解析一遍Token, 浪费资源。我们可以直接将Filter中解析好了的用户ID直接通过Header传递给接口啊。

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String token = request.getHeader("token");
JWTResult result = JWTUtils.checkToken(token);
Long userId = result.getUserId();
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest) {
@Override
public String getHeader(String name) {
if (name.equals("loginUserId")) {
return userId .toString();
}
return super.getHeader(name);
}
};
chain.doFilter(requestWrapper, httpResponse);
}

接口中直接从Header中获取解析好了的用户ID:

@GetMapping("/hello")
public String save2(HttpServletRequest request) {
Long userId = Long.parseLong(request.getHeader("loginUserId"));
}

方式三(很优雅)

通过Header传递确实很方便,但如果你有代码洁癖的话总会觉得怪怪的,能不能不用Header方式,比如说我就在方法上定义一个loginUserId的参数,你给我直接注入进来,这个有点意思哈,下面我们来实现下:

GET参数方式

在Filter中追加参数:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String token = request.getHeader("token");
JWTResult result = JWTUtils.checkToken(token);
Long userId = result.getUserId();
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest) {
@Override
public String[] getParameterValues(String name) {
if (name.equals("loginUserId")) {
return new String[] { userId .toString() };
}
return super.getParameterValues(name);
}
@Override
public Enumeration<String> getParameterNames() {
Set<String> paramNames = new LinkedHashSet<>();
paramNames.add("loginUserId");
Enumeration<String> names = super.getParameterNames();
while(names.hasMoreElements()) {
paramNames.add(names.nextElement());
}
return Collections.enumeration(paramNames);
}
};
chain.doFilter(requestWrapper, httpResponse);
}

接口中直接填写参数即可获取:

@GetMapping("/hello")
public String save2(String name, Long loginUserId) {
// loginUserId 就是Filter中追加的值
}

对于post请求,也可以用这种方式:

@PostMapping("/hello")
public String save2(User user, Long loginUserId) { }

可是往往我们在用post请求的时候,要么就是表单提交,要么就是json体的方式提交,一般不会使用get方式参数,这也就意味着这个loginUserId我们需要注入到对象中:

先创建一个参数实体类:

public class User {

	private String name;

	private Long loginUserId;
}

先模拟表单提交的方式,看看行不行:

@PostMapping("/hello")
public User save2(User user) {
return user;
}

用PostMan测试一下,表单方式是直接支持的:

再次试下Json提交方式:

@PostMapping("/hello")
public User save2(@RequestBody User user) {
return user;
}

看下图,失败了,得重新想办法实现下

只需要在HttpServletRequestWrapper中重新对提交的内容进行修改即可:

@Override
public ServletInputStream getInputStream() throws IOException {
byte[] requestBody = new byte[0];
try {
requestBody = StreamUtils.copyToByteArray(request.getInputStream());
Map map = JsonUtils.toBean(Map.class, new String(requestBody));
map.put("loginUserId", loginUserId);
requestBody = JsonUtils.toJson(map).getBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
} @Override
public boolean isFinished() {
return false;
} @Override
public boolean isReady() {
return true;
} @Override
public void setReadListener(ReadListener listener) { }
};
}

到此为止,我们就可以直接将Token解析的用户ID直接注入到参数中了,不用去Header中获取,是不是很方便。

欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)

PS:目前星球中正在星主的带领下组队学习Spring Cloud,等你哦!

Token认证,如何快速方便获取用户信息的更多相关文章

  1. 再谈Token认证,如何快速方便获取用户信息

    前面我写了一篇<Token认证,如何快速方便获取用户信息>的文章,引起了各位读者的积极参与,除了文章中我提出的三种方式,各位读者大佬们也贡献了其他多种实现方式. 今天决定基于大家提供的思路 ...

  2. 从SpringMVC获取用户信息谈起

    Github地址:https://github.com/andyslin/spring-ext 编译.运行环境:JDK 8 + Maven 3 + IDEA + Lombok spring-boot: ...

  3. 微信快速开发框架(八)-- V2.3--增加语音识别及网页获取用户信息,代码已更新至Github

    不知不觉,版本以每周更新一次的脚步进行着,接下来应该是重构我的代码及框架的结构,有朋友反应代码有点乱,确实如此,当时写的时候只是按照订阅号来写的,后来才慢慢增加到支持API接口.目前还在开发第三方微信 ...

  4. .NET微信开发通过Access Token和OpenID获取用户信息

    本文介绍如何获得微信公众平台关注用户的基本信息,包括昵称.头像.性别.国家.省份.城市.语言. 本文的方法将囊括订阅号和服务号以及自定义菜单各种场景,无论是否有高级接口权限,都有办法来获得用户基本信息 ...

  5. Spring Cloud云架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)

    上一篇我根据框架中OAuth2.0的使用总结,画了SSO单点登录之OAuth2.0 登出流程,今天我们看一下根据用户token获取yoghurt信息的流程: /** * 根据token获取用户信息 * ...

  6. 整合spring cloud云架构 - 根据token获取用户信息

    根据用户token获取yoghurt信息的流程: /** * 根据token获取用户信息 * @param accessToken * @return * @throws Exception */ @ ...

  7. 微信第三方登陆,无需注册一键登录,获取用户信息,PHP实现方法

    今天讲讲利用微信oauth2实现第三方登陆的实现方法. 先说说前提吧! 首先你得是服务号,并且是经过认证的.这样微信会给你很多第三方接口的权限,如果是订阅号或者没有认证的服务号那就不用想了! 一开始你 ...

  8. JAVA获取微信小程序openid和获取公众号openid,以及通过openid获取用户信息

    一,首先说明下这个微信的openid 为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,如果需要在多公众号.移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开 ...

  9. Laravel OAuth2 (一) ---简单获取用户信息

    前言 本来要求是使用微信进行第三方登陆,所以想着先用 github 测试成功再用微信测试,可是最近拖了好久都还没申请好微信开放平台的 AppID ,所以就只写 github 的第三方登陆吧,估计微信的 ...

随机推荐

  1. Java电商项目-3.使用VSFTPD_Nginx完成商品新增

    目录 到Github获取源码请点击此处 一. 商品类目查询 二. FTP图片服务器的搭建 图片上传思路介绍 Linux中安装vsftpd 接着配置ftp服务, 让外网可以访问 Http服务器搭建 Ng ...

  2. 动态类型dynamic转换为特定类型T的方案

    需求场景:有时候我们抓到一段请求数据,JSON格式的字符串数据,需要放在接口里重现问题,我们就可能会用dynamic先接受数据,然后再转换成特定数据发出请求. 方案一:直接使用特定对象T,来接受请求数 ...

  3. python基础(33):线程(一)

    1. 线程概念的引入背景 1.1 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在 ...

  4. Python【day 17】面向对象-成员

    类的变量分成2种: 1.成员变量 概念:在构造方法中的变量,前面带有self 作用:可以在类中不同的方法间使用 2.类变量-静态变量 概念:在类中,构造方法和普通方法之外,定义的变量 作用: 1.调用 ...

  5. 性能优化之mybatis实现接口的批量查询,减少数据库的查询消耗

    <select id="selectByTime" resultType="com.neo.xnol.api.activity.dto.ActivityMqmsgD ...

  6. 微信小程序 setData 如何修改动态数据?

    最近这段时间在写微信小程序,有一个页面需要动态修改 data 中的数据,而这里似乎是个坑. 1.正常修改 正常修改很简单,当触发 change 事件时,数据和页面都会同时发生改变.这个也不用多说,很简 ...

  7. 细数C++中的for循环

    1.for(;;)这个是最基础最简单的for循环,从刚开始学习C语言的时候就知道的.for(int i = 0; i < 10; ++i){ }2.foreach完整的是for each(obj ...

  8. MySQL报错注入总结

    mysql暴错注入方法整理,通过floor,UpdateXml,ExtractValue,NAME_CONST,Error based Double Query Injection等方法. 报错注入: ...

  9. 关于OC中直接打印结构体(CGRectCGSize、CGPoint、UIOffset)等数据类型

    关于OC直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型,我们完全可以把其转换为OC对象来进项打印调试,而不必对结构体中的成员变量进行打印.就好比我们可以使 ...

  10. Linux命令大全|linux常用命令

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...