首页 > 编程 > Java > 正文

gateway和jwt网关认证实现过程解析

2019-11-26 08:21:13
字体:
来源:转载
供稿:网友

这篇文章主要介绍了gateway和jwt网关认证实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

思路: 全局过滤器对所有的请求拦截(生成token有效期30分钟,放入redis设置有效期3天。3天之类可以通过刷新接口自动刷新,超过3天需要重新登录。)

前端在调用接口之前先判断token是否过期(3o分钟),过期则先调刷新接口,换取新token,

1引入相关jar

<dependency>      <groupId>org.springframework.cloud</groupId>      <artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency>      <groupId>io.jsonwebtoken</groupId>      <artifactId>jjwt</artifactId>      <version>0.9.0</version></dependency>

2编写Jwt工具类(生成token + 解析token)

package spring.cloud.gateway.common;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.util.HashMap;import java.util.Map;import io.jsonwebtoken.ExpiredJwtException;import org.springframework.util.StringUtils;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;public class JwtUtil {  public static final String SECRET = "qazwsx123444$#%#()*&& asdaswwi1235 ?;!@#kmmmpom in***xx**&";  public static final String TOKEN_PREFIX = "Bearer";  public static final String LOGIN_URL = "/token/userId/pwd";  public static final String LOGOUT_URL = "/token/userId";  public static final String HEADER_AUTH = "authorization";  public static final String HEADER_USERID = "userid";  //token超时时间  public static final int TOKEN_EXPIRATION_MINUTE = 30;  //token的redis超时时间  public static final int TOKEN_REDIS_EXPIRATION_DAY = 7;    public static String generateToken(String userId) {    Calendar calendar = Calendar.getInstance();    calendar.add(Calendar.MINUTE, TOKEN_EXPIRATION_MINUTE); //得到前一天    Date date = calendar.getTime();    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    df.format(date);    //todo 优化token的生层规则    HashMap<String, Object> map = new HashMap<>();    map.put(HEADER_USERID, userId);    String jwt = Jwts.builder()        .setSubject(HEADER_USERID).setClaims(map)        .setExpiration(date)        .signWith(SignatureAlgorithm.HS512, SECRET)        .compact();    return TOKEN_PREFIX + " " + jwt;  }  public static Map<String, String> validateToken(String token) {    HashMap<String, String> tokenMap = new HashMap<String, String>();    if (StringUtils.isEmpty(token)) {      return tokenMap;    }    try {      Map<String, Object> tokenBody = Jwts.parser()          .setSigningKey(SECRET)          .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))          .getBody();      String userId = String.valueOf(tokenBody.get(HEADER_USERID));      tokenMap.put(HEADER_USERID, userId);    }catch (ExpiredJwtException e){      e.printStackTrace();    }    return tokenMap;  }  /**   * 移到jwtUtil中去   *   * @param token   * @return   */  public static Map<String, String> validateTokenAndUser(String token, String userIdIn) {    Map<String, String> tokenResultMap = new HashMap<>();    if (StringUtils.isEmpty(token) || StringUtils.isEmpty(userIdIn)) {      return tokenResultMap;    }    tokenResultMap = validateToken(token);    if (StringUtils.isEmpty(token) || StringUtils.isEmpty(userIdIn)) {      return tokenResultMap;    }    //判断传入的userid和token是否匹配    String userIdOri = tokenResultMap.get(HEADER_USERID);    if (!userIdIn.equals(userIdOri)) {      return new HashMap<String,String>();    }    return tokenResultMap;  }}

3编写过滤器类

package spring.cloud.gateway.filter;import java.net.URI;import java.util.Map;import org.apache.commons.lang.StringUtils;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.cloud.gateway.route.Route;import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpMethod;import org.springframework.http.server.PathContainer;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.stereotype.Component;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Mono;import spring.cloud.gateway.common.JwtUtil;import spring.cloud.gateway.exception.PermissionException;/** * 参数参考 https://blog.csdn.net/tianyaleixiaowu/article/details/83375246 * response参考 https://bbs.csdn.net/topics/392412604?list=11074255 */@Componentpublic class AuthFilter implements GlobalFilter {  @Override  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {    ServerHttpRequest request = exchange.getRequest();    HttpHeaders header = request.getHeaders();    HttpMethod method = request.getMethod();    String token = header.getFirst(JwtUtil.HEADER_AUTH);    String userId = header.getFirst(JwtUtil.HEADER_USERID);    PathContainer pathContainer = request.getPath().pathWithinApplication();    String path = pathContainer.value();    //2- 处理登录请求    if (StringUtils.isBlank(token)) {      //是登录接口则放行,否则返回异常      if (path.contains(JwtUtil.LOGIN_URL) && HttpMethod.POST.equals(method)) {        throw new PermissionException("please login");      }      return chain.filter(exchange);    }    //3- 处理刷新token请求    if (path.indexOf("refresh") >= 0) {      //放行去掉刷新接口(在刷新前校验userId和token是否匹配)      return chain.filter(exchange);    }    //4- 处理刷新token请求    if (path.contains(JwtUtil.LOGOUT_URL) && HttpMethod.DELETE.equals(method)) {      //放行去掉登出接口(在刷新前校验userId和token是否匹配)      return chain.filter(exchange);    }    //5- 携带token请求其他业务接口    Map<String, String> validateResultMap = JwtUtil.validateTokenAndUser(token, userId);    if (validateResultMap == null || validateResultMap.isEmpty()) {      throw new PermissionException("token 已经失效");    }    // TODO 将用户信息存放在请求header中传递给下游业务    Route gatewayUrl = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);    URI uri = gatewayUrl.getUri();    //表示下游请求对应的服务名如 SPRING-CLOUD-SERVICE SPRING-CLOUD-GATEWAY    String serviceName = uri.getHost();    ServerHttpRequest.Builder mutate = request.mutate();    mutate.header("x-user-id", validateResultMap.get("userid"));    mutate.header("x-user-name", validateResultMap.get("user"));    mutate.header("x-user-serviceName", serviceName);    ServerHttpRequest buildReuqest = mutate.build();    //todo 如果响应中需要放数据,也可以放在response的header中    //ServerHttpResponse response = exchange.getResponse();    //response.getHeaders().add("new_token","token_value");    return chain.filter(exchange.mutate().request(buildReuqest).build());  }}

4编写相关接口API

package spring.cloud.gateway.controller;import org.springframework.web.bind.annotation.*;import spring.cloud.gateway.common.JwtUtil;import java.util.Map;@RestController@RequestMapping("/token")public class TokenController {  /**   * 登录接口   * @param user(userID +pwd)   * @return   */  @PostMapping("/userId/pwd")  public String getToken(@RequestBody Map<String,String> user) {    //用户名密码需要加密处理    String result = "";    if (user == null || user.isEmpty()) {      return result;    }    String userId = user.get("userId");    String pwd = user.get("pwd");    if (!doLogin(userId,pwd)) {      return result;    }    String token = JwtUtil.generateToken(userId);    // todo 将token放入redis中,设置超时时间为 2 * t    return token;  }  private Boolean doLogin(String userId,String pwd) {    //后续对接user表验证    if ("admin".equals(userId) && "123".equals(pwd)) {      return true;    }    if ("spring".equals(userId) && "123".equals(pwd)) {      return true;    }    if ("gateway".equals(userId) && "123".equals(pwd)) {      return true;    }    return false;  }  /**   * 登出接口   */  /**   * 刷新token的接口   * 在刷新前校验userId和token是否匹配   */}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表