Spring Cloud Gateway 使用JWT工具类做用户登录校验

举报
兴趣使然的草帽路飞 发表于 2021/06/08 23:09:49 2021/06/08
【摘要】 1. JWT测试 /** * @Auther: csp1999 * @Date: 2021/01/24/19:29 * @Description: JWT测试 */ public class JwtTest { /** * 创建Jwt令牌: * * JWT = 头部Header + 载荷playload + 签名signature */ @Test publi...

1. JWT测试

/**
 * @Auther: csp1999
 * @Date: 2021/01/24/19:29
 * @Description: JWT测试
 */
public class JwtTest { /** * 创建Jwt令牌: * * JWT = 头部Header + 载荷playload + 签名signature */ @Test public void testCreateJwt() { // 构建jwt令牌 // 1.头部Header: 描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等 JwtBuilder builder = Jwts.builder() .setId("8989") // 设置令牌唯一编号 .setIssuer("csp1999") // 设置令牌颁发者 .setSubject("JWT加密测试") //  设置令牌主题  可以是JSON数据 .setIssuedAt(new Date()) // 设置令牌签发日期 .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 3));// 设置令牌过期时间 3分钟 // 2.自定义载荷playload: 存放有效信息的地方 Map<String,Object> userInfo = new HashMap<>(); userInfo.put("username","csp"); userInfo.put("password","123456"); userInfo.put("school","河南科技大学"); userInfo.put("age","22"); // 将载荷添加到JWT令牌中 builder.addClaims(userInfo); // 3.为令牌设置 签名signature builder.signWith(SignatureAlgorithm.HS256, "haust");// 设置令牌的签名 使用HS256算法,并设置SecretKey密钥(字符串) // 构建 并返回一个字符串 String jwtStr = builder.compact(); System.out.println(jwtStr); } /** * 解析Jwt令牌数据 */ @Test public void testParseJwt() { // jwt字符串 String jwtStr = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4OTg5IiwiaXNzIjoiY3NwMTk5OSIsInN1YiI6IkpXVOWKoOWvhua1i-ivlSIsImlhdCI6MTYxMTQ4ODc1MSwiZXhwIjoxNjExNDg4OTMxLCJwYXNzd29yZCI6IjEyMzQ1NiIsInNjaG9vbCI6Iuays-WNl-enkeaKgOWkp-WtpiIsImFnZSI6IjIyIiwidXNlcm5hbWUiOiJjc3AifQ.uH28G9MSHfzaKBAOyr8AdksYLVvy8O5P8g7TORZIUFY"; // 解析jwt字符串 Claims claims = Jwts.parser(). setSigningKey("haust"). // 密钥(盐) parseClaimsJws(jwtStr). // 要解析的令牌对象 getBody(); // 获取解析后的结果 // {jti=8989, iss=csp1999, sub=JWT加密测试, iat=1611488751, exp=1611488931, password=123456, school=河南科技大学, age=22, username=csp} System.out.println(claims); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

2. JWT工具类

/**
 * @Auther: csp1999
 * @Date: 2021/01/24/19:29
 * @Description: JWT工具类
 */
public class JwtUtil { // 有效期为 public static final Long JWT_TTL = 3600000L;// 60 * 60 * 1000  一个小时 // Jwt令牌信息 public static final String JWT_KEY = "itcast"; /** * 生成令牌 * @param id * @param subject * @param ttlMillis * @return */ public static String createJWT(String id, String subject, Long ttlMillis) { // 指定算法 SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; // 当前系统时间 long nowMillis = System.currentTimeMillis(); // 令牌签发时间 Date now = new Date(nowMillis); // 如果令牌有效期为null,则默认设置有效期1小时 if (ttlMillis == null) { ttlMillis = JwtUtil.JWT_TTL; } // 令牌过期时间设置 long expMillis = nowMillis + ttlMillis; Date expDate = new Date(expMillis); // 生成秘钥 SecretKey secretKey = generalKey(); // 封装Jwt令牌信息 JwtBuilder builder = Jwts.builder() .setId(id) //唯一的ID .setSubject(subject) // 主题  可以是JSON数据 .setIssuer("admin") // 签发者 .setIssuedAt(now) // 签发时间 .signWith(signatureAlgorithm, secretKey) // 签名算法以及密匙 .setExpiration(expDate); // 设置过期时间 return builder.compact(); } /** * 生成加密 secretKey * * @return */ public static SecretKey generalKey() { byte[] encodedKey = Base64.getEncoder().encode(JwtUtil.JWT_KEY.getBytes()); SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); return key; } /** * 解析令牌数据 * * @param jwt * @return * @throws Exception */ public static Claims parseJWT(String jwt) throws Exception { SecretKey secretKey = generalKey(); return Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(jwt) .getBody(); } public static void main(String[] args) { String jwt = JwtUtil.createJWT("weiyibiaoshi", "aaaaaa", null); System.out.println(jwt); try { Claims claims = JwtUtil.parseJWT(jwt); System.out.println(claims); } catch (Exception e) { e.printStackTrace(); } }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

3. 用户登录校验

3.1 网关过滤器

/**
 * @Auther: csp1999
 * @Date: 2021/01/24/20:17
 * @Description: 授权过滤器
 */
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered { // 令牌头名字 private static final String AUTHORIZE_TOKEN = "Authorization"; /** * 全局过滤器 * * @param exchange * @param chain * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取Request、Response对象 ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); // 获取请求的URI String path = request.getURI().getPath(); // 如果是登录、goods等开放的微服务[这里的goods部分开放],则直接放行,这里不做完整演示,完整演示需要设计一套权限系统 // 未登录下只放行登录和搜索 if (path.startsWith("/api/user/login") || path.startsWith("/api/brand/search/")) { // 放行 Mono<Void> filter = chain.filter(exchange); return filter; } // 从头文件中获取的令牌信息 String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN); // 如果为true:说明令牌在头文件中, false:令牌不在头文件中,将令牌封装入头文件,再传递给其他微服务 boolean hasToken = true; // 如果头文件中没有令牌信息,则从请求参数中获取 if (StringUtils.isEmpty(token)) { token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN); hasToken = false; } // 如果为空,则输出错误代码 if (StringUtils.isEmpty(token)) { // 设置方法不允许被访问,405错误代码 response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED); return response.setComplete(); } // 如果不为空,则解析令牌数据 try { Claims claims = JwtUtil.parseJWT(token); } catch (Exception e) { e.printStackTrace(); // 解析失败,响应401错误 response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } // 放行之前,将令牌封装到头文件中(这一步是为了方便AUTH2校验令牌) request.mutate().header(AUTHORIZE_TOKEN,token); // 放行 return chain.filter(exchange); } /** * 过滤器执行顺序 * * @return */ @Override public int getOrder() { // 首位 return 0; }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

3.2 网关微服务application.yml

spring:
  cloud: gateway: globalcors: corsConfigurations: '[/**]': # 匹配所有请求 allowedOrigins: "*" # 跨域处理 允许所有的域 allowedMethods: #支持的请求类型 - GET - POST - PUT - DELETE routes: # 对接商品goods微服务路由相关配置 - id: changgou_goods_route uri: lb://changgou-goods predicates: - Path=/api/brand/**,/api/category/** filters: - StripPrefix=1 - name: RequestRateLimiter # 请求数限流 名字不能随便写 ,使用默认的facatory args: # 用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。 key-resolver: "#{@ipKeyResolver}" # 令牌桶每秒填充平均速率 redis-rate-limiter.replenishRate: 1 # 令牌桶总容量 redis-rate-limiter.burstCapacity: 1 # 上面配置,表示1秒内,允许 1个请求通过,令牌桶的填充速率也是1秒钟添加1个令牌。 # 对接用户user微服务路由相关配置 - id: changgou_user_route uri: lb://changgou-user predicates: - Path=/api/user/**,/api/address/**,/api/areas/**,/api/cities/**,/api/provinces/** filters: # user微服务真实请求中是没有/api的,所以这里StripPrefix=1 - StripPrefix=1
  # 微服务名称
  application: name: changgou-gateway-web
  # Redis配置
  redis: # Redis数据库索引(默认为0) database: 0 # Redis服务器地址 host: 8.131.66.136 # Redis服务器连接端口 port: 6379 # Redis服务器连接密码(默认为空) password: csp19990129

server:
  port: 8001
eureka:
  client: service-url: defaultZone: http://127.0.0.1:7001/eureka
  instance: prefer-ip-address: true
management:
  endpoint: gateway: enabled: true web: exposure: include: true

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

3.3 网关微服务主启动类

/**
 * @Auther: csp1999
 * @Date: 2021/01/24/15:16
 * @Description: 用户/前台微服务网关启动类
 */
@SpringBootApplication
@EnableEurekaClient
public class GatewayWebApplication { public static void main(String[] args) { SpringApplication.run(GatewayWebApplication.class, args); } /** * IP限流:由用户请求的IP创建创建用户唯一标识,进而根据IP进行限流操作 * * @return */ @Bean(name = "ipKeyResolver") public KeyResolver userKeyResolver() { return new KeyResolver() { @Override public Mono<String> resolve(ServerWebExchange exchange) { // 获取远程客户端IP String hostName = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress(); System.out.println("hostName:" + hostName); return Mono.just(hostName); } }; }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

3.4 用户微服务编写登录代码

/**
 * @Author: csp1999
 * @Description: User 的Controller
 * @Date 2021/1/14 0:18
 */
@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController { @Autowired private UserService userService; /*** * 修改User数据 * @param user * @param id * @return */ @PutMapping(value = "/{id}") public Result update(@RequestBody User user, @PathVariable String id) { ... } /*** * 新增User数据 * @param user * @return */ @PostMapping public Result add(@RequestBody User user) { ... } /*** * 根据ID查询User数据 * @param id * @return */ @GetMapping("/{id}") public Result<User> findById(@PathVariable String id) { ... } /*** * 查询User全部数据 * @return */ @GetMapping public Result<List<User>> findAll() { ... } /*** * 用户登录 * @param username * @param password * @param response * @param request * @return */ @RequestMapping("/login") public Result<User> login(String username, String password, HttpServletResponse response, HttpServletRequest request) { // 1.从数据库中查询用户名对应的用户的对象 User user = userService.findById(username); if (user == null) { // 2.判断用户是否为空 为空返回数据 return new Result<User>(false, StatusCode.LOGINERROR, "用户名或密码错误..."); } // 3.如果不为空 判断密码是否正确 若正确 则登录成功 if (BCrypt.checkpw(password, user.getPassword())) { // 登录成功,讲用户信息存入map Map<String, Object> info = new HashMap<String, Object>(); info.put("role", "USER"); info.put("success", "SUCCESS"); info.put("username", username); // 3.1生成令牌 String jwt = JwtUtil.createJWT(UUID.randomUUID().toString(), JSON.toJSONString(info), null); // 3.2设置jwt存入 cookie 中 Cookie cookie = new Cookie("Authorization", jwt); response.addCookie(cookie); // 3.3设置jwt存入头文件中 response.setHeader("Authorization", jwt); return new Result<User>(true, StatusCode.OK, "登录成功", jwt); } else { // 登录失败 return new Result<User>(false, StatusCode.LOGINERROR, "用户名或密码错误"); } }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

文章来源: csp1999.blog.csdn.net,作者:兴趣使然の草帽路飞,版权归原作者所有,如需转载,请联系作者。

原文链接:csp1999.blog.csdn.net/article/details/113096252

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。