欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Getway jwt 单点登录以及刷新token时间

程序员文章站 2022-04-07 18:05:20
Getway jwt 单点登录以及刷新token时间不用nosql或其他1.集成jwtpom依赖: io.jsonwebtoken jjwt 0.9.0 2.jwt工具类packa...

Getway jwt 单点登录以及刷新token时间

不用nosql或其他
1.集成jwt
pom依赖:

 <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.9.0</version>
    </dependency>

2.jwt工具类

package com.zkhx.uitls;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @author kai
 * @since 2020
 */
public class JwtUtils {

    //设置token过期时间
//    public static final long EXPIRE = 1000 * 60 * 60 * 24;
    public static final long EXPIRE = 2000 * 60;
    //加密秘钥,可以随便写
    public static final String KAI_SECRET = "xxxxxxxxxxxxx";

    //这个是生成token的方法,参数可多个
    public static String getJwtToken(String id, String nickname){

        String JwtToken = Jwts.builder()
                //这个是头信息
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")

                //这里是设置过期时间
                .setSubject("kj-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))

                //设置token的主体信息,存储用户信息
                .claim("id", id)
                .claim("nickname", nickname)
                //.claim("xxx", xxx)

                //签发hash  根据KAI_SECRET秘钥  HS256方式生成
                .signWith(SignatureAlgorithm.HS256, KAI_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * 判断token是否存在与有效
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断token是否存在与有效
     * @param request
     * @return
     */
    public static boolean checkToken(HttpServletRequest request) {
        try {
            String jwtToken = request.getHeader("token");
            if(StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);//根据秘钥解析,如果异常,则返回false
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取会员id
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("id");
    }

    /**
     * 根据token获取nickname
     * @param request
     * @return
     */
    public static String getNameByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("nickname");
    }

   
}

用户服务登录获取token

package com.zkhx.dept.controller;

import com.github.pagehelper.PageInfo;
import com.zkhx.dept.service.UserService;
import com.zkhx.entity.UnitEntity;
import com.zkhx.entity.UserEntity;
import com.zkhx.uitls.JwtUtils;
import com.zkhx.uitls.MD5;
import com.zkhx.uitls.ResultCode;
import com.zkhx.uitls.ResultMsg;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author qinKJ
 * @version 1.0
 * @date 2020.12.7 11:50
 */
@RestController
@Slf4j
@RequestMapping("/xxx/xxx")
@Api(tags = "",description = "")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/UserController/userLogin")
    public ResultMsg userLogin(@RequestParam("username") String username,@RequestParam("password") String password){
        try {
            UserEntity userEntity=new UserEntity();
            userEntity.setPassword(MD5.encrypt(password));
            userEntity.setUsername(username);
            UserEntity userEntity1 = userService.userLogin(userEntity);
            if(userEntity1!=null&&!userEntity1.equals("")){
                String jwtToken = JwtUtils.getJwtToken(String.valueOf(userEntity1.getId()), userEntity1.getUsername());
                return ResultMsg.successMsg().data(jwtToken);
            }else {
                return ResultMsg.failMsg(ResultCode.DATANULL,"登录失败,请检查用户名和密码是否正确");
            }
        }catch (Exception e){
            return ResultMsg.failMsg(ResultCode.ERROR,"发生异常");
        }
    }
}

Getway jwt 单点登录以及刷新token时间
getway服务
依赖

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
      <version>${boot-version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
      <version>${boot-version}</version>
    </dependency>

    <!--jwt-->
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.9.0</version>
    </dependency>

getway与web是有冲突的,servlet不能用,用 的ServerHttpRequest ServerHttpResponse
原jwt工具类是涉及到servlet的,复制改造jwt工具类到网关服务

package com.zkhx.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;

import java.util.Date;

/**
 * @author qinKJ
 * @version 1.0
 * @date 2020.12.30 10:55
 */
public class JwtUtil {
    public static final String KAI_SECRET = "xxxxx";

    //设置token过期时间
    //    public static final long EXPIRE = 1000 * 60 * 60 * 24;
    public static final long EXPIRE = 2000 * 60;

    //这个是生成token的方法,参数可多个
    public static String getJwtToken(String id, String nickname){

        String JwtToken = Jwts.builder()
                //这个是头信息
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")

                //这里是设置过期时间
                .setSubject("kj-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))

                //设置token的主体信息,存储用户信息
                .claim("id", id)
                .claim("nickname", nickname)
                //.claim("xxx", xxx)

                //签发hash  根据KAI_SECRET秘钥  HS256方式生成
                .signWith(SignatureAlgorithm.HS256, KAI_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * 判断token是否存在与有效
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取nickname
     * @param jwtToken
     * @return
     */
    public static String getNameByJwtToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("nickname");
    }

    /**
     * 根据token获取会员id
     * @param jwtToken
     * @return
     */
    public static String getMemberIdByJwtToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("id");
    }

    /**
     * 判断是可以刷新token,根据自己的业务来
     * @param token
     * @param lastPasswordReset
     * @return
     */
    public static Boolean canTokenBeRefreshed(String token, Date xxx) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(KAI_SECRET)
                    .parseClaimsJws(token)
                    .getBody();
            final Date iat = claims.getIssuedAt();
            final Date exp = claims.getExpiration();
            if (iat.before(xxx) || exp.before(new Date())) {
                return false;
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 刷新token
     * @param token
     * @param id
     * @param nickname
     * @return
     */
    public static String refreshToken(String token,String id, String nickname) {
        String refreshedToken;
        try {
            final Claims claims = Jwts.parser()
                    .setSigningKey(KAI_SECRET)
                    .parseClaimsJws(token)
                    .getBody();
            refreshedToken = getJwtToken(id, nickname);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }
}

网关拦截器

package com.zkhx.filter;

import com.google.gson.JsonObject;
import com.zkhx.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @author qinKJ
 * @version 1.0
 * @date 2020.12.30 9:50
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        ServerHttpResponse response = exchange.getResponse();
        //校验用户必须登录
        if(antPathMatcher.match("/phm/fault/**", path)) {
            List<String> tokenList = request.getHeaders().get("token");
            String tokenJwt=request.getHeaders().getFirst("token");
            if(null == tokenList) {
//                ServerHttpResponse response = exchange.getResponse();
                return out(response);
            } else if(JwtUtil.checkToken(tokenJwt)) {
                String nameByJwtToken = JwtUtil.getNameByJwtToken(tokenJwt);
                String memberIdByJwtToken = JwtUtil.getMemberIdByJwtToken(tokenJwt);
****************************************************************测试用****************************************************************
                Claims claims1 = Jwts.parser()
                        .setSigningKey("ukc8BDbRigUDaY6pZFfWus2jZWLPHO")
                        .parseClaimsJws(tokenJwt)
                        .getBody();

                Date d1 = claims1.getIssuedAt();
                Date d2 = claims1.getExpiration();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                System.out.println("username参数值:" + claims1.get("username"));
                System.out.println("登录用户的id:" + claims1.getId());
                System.out.println("登录用户的名称:" + claims1.getSubject());
                System.out.println("令牌签发时间:" + sdf.format(d1));
                System.out.println("令牌过期时间:" + sdf.format(d2));

                Boolean aBoolean = JwtUtil.canTokenBeRefreshed(tokenJwt, new Date());
                if (!aBoolean){
                    tokenJwt=JwtUtil.refreshToken(tokenJwt,memberIdByJwtToken,nameByJwtToken);
                    Claims claims2 = Jwts.parser()
                            .setSigningKey(JwtUtil.KAI_SECRET)
                            .parseClaimsJws(tokenJwt)
                            .getBody();

                    Date d3 = claims2.getIssuedAt();
                    Date d4 = claims2.getExpiration();
                    System.out.println("username参数值:" + claims2.get("username"));
                    System.out.println("登录用户的id:" + claims2.getId());
                    System.out.println("登录用户的名称:" + claims2.getSubject());
                    System.out.println("令牌签发时间:" + sdf.format(d3));
                    System.out.println("令牌过期时间:" + sdf.format(d4));

                    // 获取响应Header,目前的实现中返回的是HttpHeaders实例,可以直接修改
                    response.getHeaders().add("new_token",tokenJwt);
                }
****************************************************************测试用****************************************************************
                // TODO 将token信息存放在请求header中传递给下游业务
                ServerHttpRequest.Builder mutate = request.mutate();
                mutate.header("AuthToken", tokenJwt);
                ServerHttpRequest buildReuqest = mutate.build();
                return chain.filter(exchange.mutate()
                        .request(buildReuqest)
                        .response(response)
                        .build());
            }else {
//                ServerHttpResponse response = exchange.getResponse();
                return out(response);
            }
        }
        //内部服务接口,不允许外部访问
        if(antPathMatcher.match("/**/knowledge/**", path)) {
//            ServerHttpResponse response = exchange.getResponse();
            return out(response);
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private Mono<Void> out(ServerHttpResponse response) {
        JsonObject message = new JsonObject();
        message.addProperty("success", false);
        message.addProperty("code", 28004);
        message.addProperty("data", "鉴权失败");
        byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        //response.setStatusCode(HttpStatus.UNAUTHORIZED);
        //指定编码,否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }
}

接下来是给访问服务加过滤
Getway jwt 单点登录以及刷新token时间

package com.zkhx.config;

/**
 * @author qinKJ
 * @version 1.0
 * @date 2020.12.30 14:13
 */

import com.zkhx.filter.TokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.List;

/**
 * 拦截器配置
 */
@Configuration
public class InterCepTerConfig implements WebMvcConfigurer {

    private TokenInterceptor tokenInterceptor;

    //构造方法
    public InterCepTerConfig(TokenInterceptor tokenInterceptor){
        this.tokenInterceptor = tokenInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        List<String> excludePath = new ArrayList<>();
//        excludePath.add("/user_register"); //注册
//        excludePath.add("/login"); //登录
//        excludePath.add("/logout"); //登出
//        excludePath.add("/static/**");  //静态资源
//        excludePath.add("/swagger-ui.html/**");  //静态资源
//        excludePath.add("/assets/**");  //静态资源

        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(excludePath);
        WebMvcConfigurer.super.addInterceptors(registry);

    }

    /**
     * 跨域支持
     *
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")
                .maxAge(3600 * 24);
    }


}

package com.zkhx.filter;

import com.alibaba.fastjson.JSONObject;
import com.zkhx.uitls.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author qinKJ
 * @version 1.0
 * @date 2020.12.30 14:07
 * 防止直接访问
 */
@Component
public class TokenInterceptor implements HandlerInterceptor {



    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{

        if(request.getMethod().equals("OPTIONS")){
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }

        response.setCharacterEncoding("utf-8");

        String token = request.getHeader("AuthToken");
        if(token != null){
            boolean result = JwtUtils.checkToken(token);
            if(result){
                return true;
            }
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try{
            JSONObject json = new JSONObject();
            json.put("success","false");
            json.put("msg","不能从这里访问哟");
            json.put("code","50000");
            response.getWriter().append(json.toJSONString());
            System.out.println("认证失败,未通过拦截器");
            //        response.getWriter().write("50000");
        }catch (Exception e){
            e.printStackTrace();
            response.sendError(500);
            return false;
        }

        return false;

    }
}

完毕,不通过网关访问接口:
Getway jwt 单点登录以及刷新token时间
登录服务获取到token,通过postman调试
Getway jwt 单点登录以及刷新token时间
Getway jwt 单点登录以及刷新token时间
Getway jwt 单点登录以及刷新token时间
替换token后再次访问
Getway jwt 单点登录以及刷新token时间
刷新成功

本文地址:https://blog.csdn.net/Helloworld_pang/article/details/111993719