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

网友投稿 272 2022-11-05


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

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(nehttp://w Date(System.currentTimeMillis() + 1000 * 60 * 3));// 设置令牌过期时间 3分钟

// 2.自定义载荷playload: 存放有效信息的地方

Map 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);

}

}

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();

}

}

}

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 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 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;

}

}

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

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 resolve(ServerWebExchange exchange) {

// 获取远程客户端IP

String hostName = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();

System.out.println("hostName:" + hostName);

return Mono.just(hostName);

}

};

}

}

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 findById(@PathVariable String id) {

...

}

/***

* 查询User全部数据

* @return

*/

@GetMapping

public Result> findAll() {

...

}

/***

* 用户登录

* @param username

* @param password

* @param response

* @param request

* @return

*/

@RequestMapping("/login")

public Result login(String username, String password, HttpServletResponse response, HttpServletRequest request) {

// 1.从数据库中查询用户名对应的用户的对象

User user = userService.findById(username);

if (user == null) {

// 2.判断用户是否为空 为空返回数据

return new Result(false, StatusCode.LOGINERROcgKiOR, "用户名或密码错误...");

}

// 3.如果不为空 判断密码是否正确 若正确 则登录成功

if (BCrypt.checkpw(password, user.getPassword())) {

// 登录成功,讲用户信息存入map

Map info = new HashMap();

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(true, StatusCode.OK, "登录成功", jwt);

} else {

// 登录失败

return new Result(false, StatusCode.LOGINERROR, "用户名或密码错误");

}

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Open Office XML 格式中的 Style 设计原理
下一篇:快递费用查询API(快递费用查询顺丰)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~