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

jujusharp  •  May 21, 2019 2:18:18 PM

原文地址


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

  1. @GetMapping("/hello")

  2. public String test(HttpServletRequest request) {

  3. String token = request.getHeader("token");

  4. JWTResult result = JWTUtils.checkToken(token);

  5. Long userId = result.getUserId();

  6. }

方式二(优雅)

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

  1. @Override

  2. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

  3. throws IOException, ServletException {

  4. HttpServletRequest httpRequest = (HttpServletRequest) request;

  5. HttpServletResponse httpResponse = (HttpServletResponse) response;

  6. String token = request.getHeader("token");

  7. JWTResult result = JWTUtils.checkToken(token);

  8. Long userId = result.getUserId();

  9. HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest) {

  10. @Override

  11. public String getHeader(String name) {

  12. if (name.equals("loginUserId")) {

  13. return userId .toString();

  14. }

  15. return super.getHeader(name);

  16. }

  17. };

  18. chain.doFilter(requestWrapper, httpResponse);

  19. }

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

  1. @GetMapping("/hello")

  2. public String save2(HttpServletRequest request) {

  3. Long userId = Long.parseLong(request.getHeader("loginUserId"));

  4. }

方式三(很优雅)

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

GET参数方式

在Filter中追加参数:

  1. @Override

  2. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

  3. throws IOException, ServletException {

  4. HttpServletRequest httpRequest = (HttpServletRequest) request;

  5. HttpServletResponse httpResponse = (HttpServletResponse) response;

  6. String token = request.getHeader("token");

  7. JWTResult result = JWTUtils.checkToken(token);

  8. Long userId = result.getUserId();

  9. HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest) {

  10. @Override

  11. public String[] getParameterValues(String name) {

  12. if (name.equals("loginUserId")) {

  13. return new String[] { userId .toString() };

  14. }

  15. return super.getParameterValues(name);

  16. }

  17. @Override

  18. public Enumeration<String> getParameterNames() {

  19. Set<String> paramNames = new LinkedHashSet<>();

  20. paramNames.add("loginUserId");

  21. Enumeration<String> names = super.getParameterNames();

  22. while(names.hasMoreElements()) {

  23. paramNames.add(names.nextElement());

  24. }

  25. return Collections.enumeration(paramNames);

  26. }

  27. };

  28. chain.doFilter(requestWrapper, httpResponse);

  29. }

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

  1. @GetMapping("/hello")

  2. public String save2(String name, Long loginUserId) {

  3. // loginUserId 就是Filter中追加的值

  4. }

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

  1. @PostMapping("/hello")

  2. public String save2(User user, Long loginUserId) {

  3. }

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

先创建一个参数实体类:

  1. public class User {

  2. private String name;

  3. private Long loginUserId;

  4. }

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

  1. @PostMapping("/hello")

  2. public User save2(User user) {

  3. return user;

  4. }

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

再次试下Json提交方式:

  1. @PostMapping("/hello")

  2. public User save2(@RequestBody User user) {

  3. return user;

  4. }

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

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

  1. @Override

  2. public ServletInputStream getInputStream() throws IOException {

  3. byte[] requestBody = new byte[0];

  4. try {

  5. requestBody = StreamUtils.copyToByteArray(request.getInputStream());

  6. Map map = JsonUtils.toBean(Map.class, new String(requestBody));

  7. map.put("loginUserId", loginUserId);

  8. requestBody = JsonUtils.toJson(map).getBytes();

  9. } catch (IOException e) {

  10. throw new RuntimeException(e);

  11. }

  12. final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);

  13. return new ServletInputStream() {

  14. @Override

  15. public int read() throws IOException {

  16. return bais.read();

  17. }

  18. @Override

  19. public boolean isFinished() {

  20. return false;

  21. }

  22. @Override

  23. public boolean isReady() {

  24. return true;

  25. }

  26. @Override

  27. public void setReadListener(ReadListener listener) {

  28. }

  29. };

  30. }

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

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

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

0 回复
暂时没有回复,你也许会成为第一个哦