整理思路:

1、用户登录或者注册后返回token给前台,并同时以userId为key,token为value存入redis

2、通过实现zuulFilter接口拦截所有通过的路由接口(单独放行登录和注册),获取请求的cookie或者请求头有没有的userId和token值跟redis预存的键值对比,相同则放行,不同则鉴权失败

主要代码实现如下:

filterType(): Filter 的类型,前置过滤器返回 PRE_TYPE

filterOrder(): Filter 的顺序,值越小越先执行。这里的写法是 PRE_DECORATION_FILTER_ORDER - 1, 也是官方建议的写法。

shouldFilter(): 是否应该过滤。返回 true 表示过滤,false 不过滤。可以在这个方法里判断哪些接口不需要过滤,本例排除了注册和登录接口,除了这两个接口,其他的都需要过滤。

run(): 过滤器的具体逻辑

1、登录测试类

@Api("登录与注册")
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@GetMapping("/login")public ApiMessage login(){stringRedisTemplate.opsForValue().set("22","bb");return ApiMessage.success("ok","bb");}}

2、zuul项目的过滤类

package com.njwd.zuul.filter;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import com.njwd.zuul.constant.ErrorCode;
import com.njwd.zuul.entity.ApiMessage;
import com.njwd.zuul.util.CookiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;/*** 权限验证 Filter* 注册和登录接口不过滤** 验证权限需要前端在 Cookie 或 Header 中(二选一即可)设置用户的 userId 和 token* 因为 token 是存在 Redis 中的,Redis 的键由 userId 构成,值是 token* 在两个地方都没有找打 userId 或 token其中之一,就会返回 400 无权限,并给与文字提示*/
@Component
public class AuthFilter extends ZuulFilter {private Logger logger = LoggerFactory.getLogger(AuthFilter.class);@AutowiredStringRedisTemplate stringRedisTemplate;//排除过滤的 uri 地址private static final String LOGIN_URI = "/common/user/login";private static final String REGISTER_URI = "/common/user/register";//无权限时的提示语private static final String INVALID_TOKEN = "invalid token";private static final String INVALID_USERID = "invalid userId";@Overridepublic String filterType() {return PRE_TYPE;}@Overridepublic int filterOrder() {return PRE_DECORATION_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {RequestContext requestContext = RequestContext.getCurrentContext();HttpServletRequest request = requestContext.getRequest();logger.info("===uri===", request.getRequestURI());//注册和登录接口不拦截,其他接口都要拦截校验 tokenif (LOGIN_URI.equals(request.getRequestURI()) ||REGISTER_URI.equals(request.getRequestURI())) {return false;}return true;}@Overridepublic Object run() throws ZuulException {RequestContext requestContext = RequestContext.getCurrentContext();HttpServletRequest request = requestContext.getRequest();//先从 cookie 中取 token,cookie 中取失败再从 header 中取,两重校验//通过工具类从 Cookie 中取出 tokenString token = CookiesUtil.getCookies(request, "token");System.out.println(token+"===========cookie===================");//不验证token时注调该代码if (token == null || StringUtils.isEmpty(token)) {readTokenFromHeader(requestContext, request);} else {verifyToken(requestContext, request, token);}return null;}/*** 从 header 中读取 token 并校验*/private void readTokenFromHeader(RequestContext requestContext, HttpServletRequest request) {//从 header 中读取String headerToken = request.getHeader("token");if (StringUtils.isEmpty(headerToken)) {setUnauthorizedResponse(requestContext, INVALID_TOKEN);} else {verifyToken(requestContext, request, headerToken);}}/*** 从Redis中校验token*/private void verifyToken(RequestContext requestContext, HttpServletRequest request, String token) {//需要从cookie或header 中取出 userId 来校验 token 的有效性,因为每个用户对应一个token,在Redis中是以 TOKEN_userId 为键的String userIdCookie = CookiesUtil.getCookies(request, "userId");String rootEnterpriseId = CookiesUtil.getCookies(request, "rootEnterpriseId");String type = request.getContentType();if (userIdCookie == null || StringUtils.isEmpty(userIdCookie)) {//从header中取userIdString userId = request.getHeader("userId");rootEnterpriseId = request.getHeader("rootEnterpriseId");if (StringUtils.isEmpty(userId)) {setUnauthorizedResponse(requestContext, INVALID_USERID);} else {String redisToken = stringRedisTemplate.opsForValue().get(userId);if (StringUtils.isEmpty(redisToken) || !redisToken.equals(token)) {setUnauthorizedResponse(requestContext, INVALID_TOKEN);}else{//针对post请求if (type != null && type.startsWith("application/json")){// 在json参数中添加 userIdtry {InputStream in = requestContext.getRequest().getInputStream();String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));System.out.println("body:" + body);JSONObject json = JSONObject.parseObject(body);json.put("userId", userIdCookie);json.put("rootEnterpriseId", rootEnterpriseId);String newBody = json.toString();System.out.println("newBody:" + newBody);final byte[] reqBodyBytes = newBody.getBytes();requestContext.setRequest(new HttpServletRequestWrapper(request){@Overridepublic ServletInputStream getInputStream() throws IOException {return new ServletInputStreamWrapper(reqBodyBytes);}@Overridepublic int getContentLength() {return reqBodyBytes.length;}@Overridepublic long getContentLengthLong() {return reqBodyBytes.length;}});} catch (IOException e) {e.printStackTrace();}}else{  //针对get请求//将转换后的数据放入请求参数中Map<String, List<String>> requestQueryParams = requestContext.getRequestQueryParams();if (requestQueryParams==null) requestQueryParams=new HashMap<>();//将要新增的参数添加进去,被调用的微服务可以直接 去取,就想普通的一样,框架会直接注入进去ArrayList<String> paramsList = new ArrayList<>();paramsList.add(rootEnterpriseId);ArrayList<String> paramsList1 = new ArrayList<>();paramsList1.add(userIdCookie);requestQueryParams.put("rootEnterpriseId", paramsList);requestQueryParams.put("userId", paramsList1);requestContext.setRequestQueryParams(requestQueryParams);}}}} else {String redisToken = stringRedisTemplate.opsForValue().get(userIdCookie);if (StringUtils.isEmpty(redisToken) || !redisToken.equals(token)) {setUnauthorizedResponse(requestContext, INVALID_TOKEN);}else{//针对post请求if (type != null && type.startsWith("application/json")){// 在json参数中添加 userIdtry {InputStream in = requestContext.getRequest().getInputStream();String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));System.out.println("body:" + body);JSONObject json = JSONObject.parseObject(body);json.put("userId", userIdCookie);json.put("rootEnterpriseId", rootEnterpriseId);String newBody = json.toString();System.out.println("newBody:" + newBody);final byte[] reqBodyBytes = newBody.getBytes();requestContext.setRequest(new HttpServletRequestWrapper(request){@Overridepublic ServletInputStream getInputStream() throws IOException {return new ServletInputStreamWrapper(reqBodyBytes);}@Overridepublic int getContentLength() {return reqBodyBytes.length;}@Overridepublic long getContentLengthLong() {return reqBodyBytes.length;}});} catch (IOException e) {e.printStackTrace();}}else{  //针对get请求//将转换后的数据放入请求参数中Map<String, List<String>> requestQueryParams = requestContext.getRequestQueryParams();if (requestQueryParams==null) requestQueryParams=new HashMap<>();//将要新增的参数添加进去,被调用的微服务可以直接 去取,就想普通的一样,框架会直接注入进去ArrayList<String> paramsList = new ArrayList<>();paramsList.add(rootEnterpriseId);ArrayList<String> paramsList1 = new ArrayList<>();paramsList1.add(userIdCookie);requestQueryParams.put("rootEnterpriseId", paramsList);requestQueryParams.put("userId", paramsList1);requestContext.setRequestQueryParams(requestQueryParams);}}}}/*** 设置 400 无权限状态*/private void setUnauthorizedResponse(RequestContext requestContext, String msg) {requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());String result = JSON.toJSONString(ApiMessage.error(ErrorCode.SIGN_ERROR_MESSAGE));requestContext.setResponseBody(result);}
}

zuul通过zuulFilter实现token的权限认证和增加公共参数相关推荐

  1. .Net Core手撸一个基于Token的权限认证

    说明 权限认证是确定用户身份的过程.可确定用户是否有访问资源的权力 今天给大家分享一下类似JWT这种基于token的鉴权机制 基于token的鉴权机制,它不需要在服务端去保留用户的认证信息或者会话信息 ...

  2. springboot+jwt实现token登陆权限认证

    目录 一 前言 二 jwt实现登陆认证流程 三 相关介绍jwt 3.1jwt 组成 3.2 jwt优点 四 jwt用户登陆发放token 4.1 pom.xml 4.2jwt工具类 4.3 用户实体 ...

  3. SpringBoot集成权限认证框架(Sa-Token)

    SpringBoot集成权限认证框架(Sa-Token) 介绍 身份验证又称"验证"."鉴权",是指通过一定的手段,完成对用户身份的确认. 身份验证的目的是确认 ...

  4. 数据权限过滤_带你实现SpringBoot整合JWT+Shiro进行权限认证「附源码地址」

    JWT JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息. 我们利用一定的编码生成 Token,并在 Token 中加入一 ...

  5. 若依微服务版怎样修改Nacos中配置文件使Url不受权限认证跳过Token验证

    场景 若依微服务版手把手教你本地搭建环境并运行前后端项目: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/109363303 在上 ...

  6. .net core 3.1JWT用户权限认证(二)获取token

    .net core 3.1JWT用户权限认证(二)获取token 直接上案列 引入程序集 第二步 建立token接口,和token实现类 public interface IJwtTokenServi ...

  7. Spring Security太复杂?试试这个轻量、强大、优雅的权限认证框架!

    各位程序猿小伙伴们,中秋快乐~在节日欢快的气氛中大家是不是还在奋笔疾书.沉浸在学习的海洋中呢? 小编这两天休息在家一直在想一个问题,那就是我们在开发SpringBoot项目的时候,该怎么做好权限认证呢 ...

  8. 这可能是史上功能最全的 Java 权限认证框架!

    点击关注公众号,回复"1024"获取2TB学习资源! 今天给大家推荐的这个开源项目超级棒,可能是史上功能最全的 Java 权限认证框架! Sa-Token 介绍 Sa-Token是 ...

  9. 详解比springSecurity和shiro更简单优雅的轻量级Sa-Token框架,比如登录认证,权限认证,单点登录,OAuth2.0,分布式Session会话,微服务网关鉴权

    文章目录 1. 技术选型 2. Sa-Token概述 2.1 简单介绍 2.2 登录认证 2.3 权限认证 3. 功能一览 4. Sa-Token使用 4.1 引入Sa-Token依赖 4.2 Sa- ...

最新文章

  1. 关于程序员的政治(转)
  2. Git -- 基本操作 之 版本回退
  3. openstack的网络、子网、端口的关系
  4. boost::fusion::filter_view用法的测试程序
  5. 三瞬属性matlab,matlab:out of memory 1
  6. db2locate函数_DB2常用函数详解
  7. php修改特定位bit的值,解读天书 - 漏洞利用中级技巧的分析
  8. 使用 Direct Initial Load 初始化 GoldenGate 同步数据
  9. 蒙提霍尔问题(三门问题,概率论)C语言验证
  10. 一道SQL题考你数据库的使用能力
  11. 计算机基础(01)基础知识
  12. 2022最新PHP微信/QQ域名防封直连系统源码
  13. orge terrain
  14. JSP打开是源码解决
  15. 一个SQL tvp+.net的例子
  16. 2008年七月七日,按照要求我提前进入中心,今天就是我博士的第一天
  17. 【机试】2011-2020年复旦大学考研复试机试真题
  18. C++HANDLE的理解
  19. 2019 - 02 typescript的学习(结合cocos creator)
  20. Oracle 聚合实现小计、合计 (GROUP BY ROLLUP)

热门文章

  1. 2022年接口测试面试题大全
  2. 蓝鲸智云实现虚拟机交付(一)
  3. android中view用法,Android中ImageView用法实例分析
  4. 易基因|MeRIP-seq揭示m6A RNA甲基化通过调控组蛋白泛素化来促进癌症生长和进展:Cancer Res
  5. 在Win10 上编译 Lineage OS 17.1 ZUK Z2 Plus备忘
  6. 普通主机装服务器系统安装,普通主机安装服务器系统安装
  7. 嘿siri_嘿siri我可以帮你吗
  8. Vue下 touchstart touchend 事件无效失效解决办法
  9. 应当怎样去做好微信营销推广呢?
  10. 2023年推出的iPhone15将使用苹果自研芯片?能行吗?