Token认证,如何快速方便获取用户信息
背景
我们有一个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认证,如何快速方便获取用户信息的更多相关文章
- 再谈Token认证,如何快速方便获取用户信息
前面我写了一篇<Token认证,如何快速方便获取用户信息>的文章,引起了各位读者的积极参与,除了文章中我提出的三种方式,各位读者大佬们也贡献了其他多种实现方式. 今天决定基于大家提供的思路 ...
- 从SpringMVC获取用户信息谈起
Github地址:https://github.com/andyslin/spring-ext 编译.运行环境:JDK 8 + Maven 3 + IDEA + Lombok spring-boot: ...
- 微信快速开发框架(八)-- V2.3--增加语音识别及网页获取用户信息,代码已更新至Github
不知不觉,版本以每周更新一次的脚步进行着,接下来应该是重构我的代码及框架的结构,有朋友反应代码有点乱,确实如此,当时写的时候只是按照订阅号来写的,后来才慢慢增加到支持API接口.目前还在开发第三方微信 ...
- .NET微信开发通过Access Token和OpenID获取用户信息
本文介绍如何获得微信公众平台关注用户的基本信息,包括昵称.头像.性别.国家.省份.城市.语言. 本文的方法将囊括订阅号和服务号以及自定义菜单各种场景,无论是否有高级接口权限,都有办法来获得用户基本信息 ...
- Spring Cloud云架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)
上一篇我根据框架中OAuth2.0的使用总结,画了SSO单点登录之OAuth2.0 登出流程,今天我们看一下根据用户token获取yoghurt信息的流程: /** * 根据token获取用户信息 * ...
- 整合spring cloud云架构 - 根据token获取用户信息
根据用户token获取yoghurt信息的流程: /** * 根据token获取用户信息 * @param accessToken * @return * @throws Exception */ @ ...
- 微信第三方登陆,无需注册一键登录,获取用户信息,PHP实现方法
今天讲讲利用微信oauth2实现第三方登陆的实现方法. 先说说前提吧! 首先你得是服务号,并且是经过认证的.这样微信会给你很多第三方接口的权限,如果是订阅号或者没有认证的服务号那就不用想了! 一开始你 ...
- JAVA获取微信小程序openid和获取公众号openid,以及通过openid获取用户信息
一,首先说明下这个微信的openid 为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,如果需要在多公众号.移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开 ...
- Laravel OAuth2 (一) ---简单获取用户信息
前言 本来要求是使用微信进行第三方登陆,所以想着先用 github 测试成功再用微信测试,可是最近拖了好久都还没申请好微信开放平台的 AppID ,所以就只写 github 的第三方登陆吧,估计微信的 ...
随机推荐
- Java电商项目-3.使用VSFTPD_Nginx完成商品新增
目录 到Github获取源码请点击此处 一. 商品类目查询 二. FTP图片服务器的搭建 图片上传思路介绍 Linux中安装vsftpd 接着配置ftp服务, 让外网可以访问 Http服务器搭建 Ng ...
- 动态类型dynamic转换为特定类型T的方案
需求场景:有时候我们抓到一段请求数据,JSON格式的字符串数据,需要放在接口里重现问题,我们就可能会用dynamic先接受数据,然后再转换成特定数据发出请求. 方案一:直接使用特定对象T,来接受请求数 ...
- python基础(33):线程(一)
1. 线程概念的引入背景 1.1 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在 ...
- Python【day 17】面向对象-成员
类的变量分成2种: 1.成员变量 概念:在构造方法中的变量,前面带有self 作用:可以在类中不同的方法间使用 2.类变量-静态变量 概念:在类中,构造方法和普通方法之外,定义的变量 作用: 1.调用 ...
- 性能优化之mybatis实现接口的批量查询,减少数据库的查询消耗
<select id="selectByTime" resultType="com.neo.xnol.api.activity.dto.ActivityMqmsgD ...
- 微信小程序 setData 如何修改动态数据?
最近这段时间在写微信小程序,有一个页面需要动态修改 data 中的数据,而这里似乎是个坑. 1.正常修改 正常修改很简单,当触发 change 事件时,数据和页面都会同时发生改变.这个也不用多说,很简 ...
- 细数C++中的for循环
1.for(;;)这个是最基础最简单的for循环,从刚开始学习C语言的时候就知道的.for(int i = 0; i < 10; ++i){ }2.foreach完整的是for each(obj ...
- MySQL报错注入总结
mysql暴错注入方法整理,通过floor,UpdateXml,ExtractValue,NAME_CONST,Error based Double Query Injection等方法. 报错注入: ...
- 关于OC中直接打印结构体(CGRectCGSize、CGPoint、UIOffset)等数据类型
关于OC直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型,我们完全可以把其转换为OC对象来进项打印调试,而不必对结构体中的成员变量进行打印.就好比我们可以使 ...
- Linux命令大全|linux常用命令
系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...