/*** @Auther: csp1999* @Date: 2021/01/24/19:29* @Description: JWT测试*/
public class JwtTest {/*** 创建Jwt令牌&#xff1a;** JWT &#61; 头部Header &#43; 载荷playload &#43; 签名signature*/&#64;Testpublic void testCreateJwt() {// 构建jwt令牌// 1.头部Header: 描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等JwtBuilder builder &#61; Jwts.builder().setId("8989") // 设置令牌唯一编号.setIssuer("csp1999") // 设置令牌颁发者.setSubject("JWT加密测试") // 设置令牌主题 可以是JSON数据.setIssuedAt(new Date()) // 设置令牌签发日期.setExpiration(new Date(System.currentTimeMillis() &#43; 1000 * 60 * 3));// 设置令牌过期时间 3分钟// 2.自定义载荷playload: 存放有效信息的地方Map<String,Object> userInfo &#61; new HashMap<>();userInfo.put("username","csp");userInfo.put("password","123456");userInfo.put("school","河南科技大学");userInfo.put("age","22");// 将载荷添加到JWT令牌中builder.addClaims(userInfo);// 3.为令牌设置 签名signaturebuilder.signWith(SignatureAlgorithm.HS256, "haust");// 设置令牌的签名 使用HS256算法&#xff0c;并设置SecretKey密钥(字符串)// 构建 并返回一个字符串String jwtStr &#61; builder.compact();System.out.println(jwtStr);}/*** 解析Jwt令牌数据*/&#64;Testpublic void testParseJwt() {// jwt字符串String jwtStr &#61; "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4OTg5IiwiaXNzIjoiY3NwMTk5OSIsInN1YiI6IkpXVOWKoOWvhua1i-ivlSIsImlhdCI6MTYxMTQ4ODc1MSwiZXhwIjoxNjExNDg4OTMxLCJwYXNzd29yZCI6IjEyMzQ1NiIsInNjaG9vbCI6Iuays-WNl-enkeaKgOWkp-WtpiIsImFnZSI6IjIyIiwidXNlcm5hbWUiOiJjc3AifQ.uH28G9MSHfzaKBAOyr8AdksYLVvy8O5P8g7TORZIUFY";// 解析jwt字符串Claims claims &#61; Jwts.parser().setSigningKey("haust"). // 密钥&#xff08;盐&#xff09;parseClaimsJws(jwtStr). // 要解析的令牌对象getBody(); // 获取解析后的结果// {jti&#61;8989, iss&#61;csp1999, sub&#61;JWT加密测试, iat&#61;1611488751, exp&#61;1611488931, password&#61;123456, school&#61;河南科技大学, age&#61;22, username&#61;csp}System.out.println(claims);}
}
/*** &#64;Auther: csp1999* &#64;Date: 2021/01/24/19:29* &#64;Description: JWT工具类*/
public class JwtUtil {// 有效期为public static final Long JWT_TTL &#61; 3600000L;// 60 * 60 * 1000 一个小时// Jwt令牌信息public static final String JWT_KEY &#61; "itcast";/*** 生成令牌* &#64;param id* &#64;param subject* &#64;param ttlMillis* &#64;return*/public static String createJWT(String id, String subject, Long ttlMillis) {// 指定算法SignatureAlgorithm signatureAlgorithm &#61; SignatureAlgorithm.HS256;// 当前系统时间long nowMillis &#61; System.currentTimeMillis();// 令牌签发时间Date now &#61; new Date(nowMillis);// 如果令牌有效期为null&#xff0c;则默认设置有效期1小时if (ttlMillis &#61;&#61; null) {ttlMillis &#61; JwtUtil.JWT_TTL;}// 令牌过期时间设置long expMillis &#61; nowMillis &#43; ttlMillis;Date expDate &#61; new Date(expMillis);// 生成秘钥SecretKey secretKey &#61; generalKey();// 封装Jwt令牌信息JwtBuilder builder &#61; Jwts.builder().setId(id) //唯一的ID.setSubject(subject) // 主题 可以是JSON数据.setIssuer("admin") // 签发者.setIssuedAt(now) // 签发时间.signWith(signatureAlgorithm, secretKey) // 签名算法以及密匙.setExpiration(expDate); // 设置过期时间return builder.compact();}/*** 生成加密 secretKey** &#64;return*/public static SecretKey generalKey() {byte[] encodedKey &#61; Base64.getEncoder().encode(JwtUtil.JWT_KEY.getBytes());SecretKey key &#61; new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 解析令牌数据** &#64;param jwt* &#64;return* &#64;throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey &#61; generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}public static void main(String[] args) {String jwt &#61; JwtUtil.createJWT("weiyibiaoshi", "aaaaaa", null);System.out.println(jwt);try {Claims claims &#61; JwtUtil.parseJWT(jwt);System.out.println(claims);} catch (Exception e) {e.printStackTrace();}}
}
/*** &#64;Auther: csp1999* &#64;Date: 2021/01/24/20:17* &#64;Description: 授权过滤器*/
&#64;Component
public class AuthorizeFilter implements GlobalFilter, Ordered {// 令牌头名字private static final String AUTHORIZE_TOKEN &#61; "Authorization";/*** 全局过滤器** &#64;param exchange* &#64;param chain* &#64;return*/&#64;Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取Request、Response对象ServerHttpRequest request &#61; exchange.getRequest();ServerHttpResponse response &#61; exchange.getResponse();// 获取请求的URIString path &#61; request.getURI().getPath();// 如果是登录、goods等开放的微服务[这里的goods部分开放],则直接放行,这里不做完整演示&#xff0c;完整演示需要设计一套权限系统// 未登录下只放行登录和搜索if (path.startsWith("/api/user/login") || path.startsWith("/api/brand/search/")) {// 放行Mono<Void> filter &#61; chain.filter(exchange);return filter;}// 从头文件中获取的令牌信息String token &#61; request.getHeaders().getFirst(AUTHORIZE_TOKEN);// 如果为true&#xff1a;说明令牌在头文件中&#xff0c; false&#xff1a;令牌不在头文件中&#xff0c;将令牌封装入头文件&#xff0c;再传递给其他微服务boolean hasToken &#61; true;// 如果头文件中没有令牌信息&#xff0c;则从请求参数中获取if (StringUtils.isEmpty(token)) {token &#61; request.getQueryParams().getFirst(AUTHORIZE_TOKEN);hasToken &#61; false;}// 如果为空&#xff0c;则输出错误代码if (StringUtils.isEmpty(token)) {// 设置方法不允许被访问&#xff0c;405错误代码response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);return response.setComplete();}// 如果不为空&#xff0c;则解析令牌数据try {Claims claims &#61; JwtUtil.parseJWT(token);} catch (Exception e) {e.printStackTrace();// 解析失败&#xff0c;响应401错误response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}// 放行之前&#xff0c;将令牌封装到头文件中(这一步是为了方便AUTH2校验令牌)request.mutate().header(AUTHORIZE_TOKEN,token);// 放行return chain.filter(exchange);}/*** 过滤器执行顺序** &#64;return*/&#64;Overridepublic int getOrder() {// 首位return 0;}
}
spring:cloud:gateway:globalcors:corsConfigurations:&#39;[/**]&#39;: # 匹配所有请求allowedOrigins: "*" # 跨域处理 允许所有的域allowedMethods: #支持的请求类型- GET- POST- PUT- DELETEroutes:# 对接商品goods微服务路由相关配置- id: changgou_goods_routeuri: lb://changgou-goodspredicates:- Path&#61;/api/brand/**,/api/category/**filters:- StripPrefix&#61;1- name: RequestRateLimiter # 请求数限流 名字不能随便写 &#xff0c;使用默认的facatoryargs:# 用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{&#64;beanName}从 Spring 容器中获取 Bean 对象。key-resolver: "#{&#64;ipKeyResolver}"# 令牌桶每秒填充平均速率redis-rate-limiter.replenishRate: 1# 令牌桶总容量redis-rate-limiter.burstCapacity: 1# 上面配置&#xff0c;表示1秒内&#xff0c;允许 1个请求通过&#xff0c;令牌桶的填充速率也是1秒钟添加1个令牌。# 对接用户user微服务路由相关配置- id: changgou_user_routeuri: lb://changgou-userpredicates:- Path&#61;/api/user/**,/api/address/**,/api/areas/**,/api/cities/**,/api/provinces/**filters:# user微服务真实请求中是没有/api的&#xff0c;所以这里StripPrefix&#61;1- StripPrefix&#61;1# 微服务名称application:name: changgou-gateway-web# Redis配置redis:# Redis数据库索引&#xff08;默认为0&#xff09;database: 0# Redis服务器地址host: 8.131.66.136# Redis服务器连接端口port: 6379# Redis服务器连接密码&#xff08;默认为空&#xff09;password: csp19990129server:port: 8001
eureka:client:service-url:defaultZone: http://127.0.0.1:7001/eurekainstance:prefer-ip-address: true
management:endpoint:gateway:enabled: trueweb:exposure:include: true
/*** &#64;Auther: csp1999* &#64;Date: 2021/01/24/15:16* &#64;Description: 用户/前台微服务网关启动类*/
&#64;SpringBootApplication
&#64;EnableEurekaClient
public class GatewayWebApplication {public static void main(String[] args) {SpringApplication.run(GatewayWebApplication.class, args);}/*** IP限流&#xff1a;由用户请求的IP创建创建用户唯一标识&#xff0c;进而根据IP进行限流操作** &#64;return*/&#64;Bean(name &#61; "ipKeyResolver")public KeyResolver userKeyResolver() {return new KeyResolver() {&#64;Overridepublic Mono<String> resolve(ServerWebExchange exchange) {// 获取远程客户端IPString hostName &#61; exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();System.out.println("hostName:" &#43; hostName);return Mono.just(hostName);}};}
}
/*** &#64;Author: csp1999* &#64;Description: User 的Controller* &#64;Date 2021/1/14 0:18*/
&#64;RestController
&#64;RequestMapping("/user")
&#64;CrossOrigin
public class UserController {&#64;Autowiredprivate UserService userService;/**** 修改User数据* &#64;param user* &#64;param id* &#64;return*/&#64;PutMapping(value &#61; "/{id}")public Result update(&#64;RequestBody User user, &#64;PathVariable String id) {...}/**** 新增User数据* &#64;param user* &#64;return*/&#64;PostMappingpublic Result add(&#64;RequestBody User user) {...}/**** 根据ID查询User数据* &#64;param id* &#64;return*/&#64;GetMapping("/{id}")public Result<User> findById(&#64;PathVariable String id) {...}/**** 查询User全部数据* &#64;return*/&#64;GetMappingpublic Result<List<User>> findAll() {...}/**** 用户登录* &#64;param username* &#64;param password* &#64;param response* &#64;param request* &#64;return*/&#64;RequestMapping("/login")public Result<User> login(String username, String password, HttpServletResponse response, HttpServletRequest request) {// 1.从数据库中查询用户名对应的用户的对象User user &#61; userService.findById(username);if (user &#61;&#61; null) {// 2.判断用户是否为空 为空返回数据return new Result<User>(false, StatusCode.LOGINERROR, "用户名或密码错误...");}// 3.如果不为空 判断密码是否正确 若正确 则登录成功if (BCrypt.checkpw(password, user.getPassword())) {// 登录成功,讲用户信息存入mapMap<String, Object> info &#61; new HashMap<String, Object>();info.put("role", "USER");info.put("success", "SUCCESS");info.put("username", username);// 3.1生成令牌String jwt &#61; JwtUtil.createJWT(UUID.randomUUID().toString(), JSON.toJSONString(info), null);// 3.2设置jwt存入 COOKIE 中COOKIE COOKIE &#61; 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, "用户名或密码错误");}}
}