1. 前言

对于后端的一些接口,有时候,我们不希望没有登录的人员访问,或者说,不希望没经过授权的人员访问。因此,我们可以在zuul这里,加一个过滤器,来验证请求头里是否带有合格的token。如果带有合格的token,说明访问者是合法登录使用人员,如果没有token或者token不合格,则不让他访问接口。

2.前端编写

2.1 请求拦截器

在main.js代码中加入下面代码。拦截向后端发送的http请求,在请求头里面,加入token(Authorization)。

//请求拦截器
axios.interceptors.request.use(
  //请求头加入token
  config =>{
    if(localStorage.getItem('Authorization')){
      config.headers.Authorization = localStorage.getItem('Authorization');
    }
    console.log(config);
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
2.2 后端验证代码

为了验证,我们加的请求拦截器是否真的生效,真的把token值加入到请求头里。我们在后端尝试打印一下请求头。修改my-user的UserController.java文件

@RequestMapping(value = "/token/test", method = RequestMethod.GET)
public void testToken(@RequestHeader Map<String,Object> header){
    System.out.println(header);
}
  • 1.
  • 2.
  • 3.
  • 4.

通过@RequestHeader Map<String,Object> header 来获取请求头,并且打印出来。

2.3 前端请求

我们在学生信息管理页面新加一个按钮,来触发这个按钮。

微服务和VUE入门教程(13): token验证-zuul拦截与验证_请求头

<el-button type="primary" @click="testToken">测试token</el-button>
  • 1.
testToken(){
  this.$axios.get('/user/token/test');
},
  • 1.
  • 2.
  • 3.
2.4 验证

当我们触发这个接口按钮时,打开后端my-user的日志,不出问题的话,打印出了请求头。我们往后拉,其中有我们加入的authorization字段。证明我们成功在请求头中加入了token值。当然,可以删除main.js中的请求拦截代码,试试后端打印出来的请求头里还带不带token。

微服务和VUE入门教程(13): token验证-zuul拦截与验证_filter_02

3. 后端zuul修改

新建filter和util文件,TokenUtil.java直接从my-user微服务中负责过来就好。

微服务和VUE入门教程(13): token验证-zuul拦截与验证_java_03

记得在pom文件中加入JWT依赖。

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
</dependency>
  • 1.
  • 2.
  • 3.
  • 4.

ZuulTokenFilter.java

package com.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.zuul.util.TokenUtil;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class ZuulTokenFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";
    }

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

    /**
     * 判断请求的接口是否需要验证token
     * 在这里,我们设定 /api/user/login,不需要验证token
     * 若不需要验证,返回false,
     * 需要验证,返回true
     *
     */
    @Override
    public boolean shouldFilter() {
        //1. 获取Zuul提供的请求上下文对象
        RequestContext requestContext = RequestContext.getCurrentContext();
        // 获取request对象
        HttpServletRequest request = requestContext.getRequest();
        if("/api/user/login".equals(request.getRequestURI())){
            return false;
        }else if(request.getMethod().equals("OPTIONS")){
            return false;
        }else {
            return true;
        }
    }

    /**
     * 若shouldFilter返回true,则运行run方法,来验证token
     * */
    @Override
    public Object run() throws ZuulException {

        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        // 获取token值
        String token = request.getHeader("authorization");
        System.out.println(token);
        // 判断是否为空
        if(token == null || "".equals(token.trim())){
            //没有token,验证失败
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }else {
            try {
                //验证token是否合格
                boolean tokenVerify = TokenUtil.verify(token);
                //如果token合格,根据请求,寻找路由
                if(tokenVerify){
                    requestContext.setSendZuulResponse(true);
                }else {
                    requestContext.setSendZuulResponse(false);
                    requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                }
            }catch (Exception e){
                requestContext.setSendZuulResponse(false);
                requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            }
        }
        return null;
    }
}
  • 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.

4. 验证

重启zuul,访问后端的接口,如果不出问题的话,zuul控制台中可以打印出下面的日志来。

微服务和VUE入门教程(13): token验证-zuul拦截与验证_filter_04

补:

TokenUtil.java

package com.zuul.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;

public class TokenUtil {
    private static final long EXPIRE_TIME = 24*60*60*1000;  //有效时长
    private static final String TOKEN_SECRET = "ben";       // 秘钥

    /**
     * 签名 生成
     * @parm userName
     * */
    public static String sign(String userName){
        String token = null;
        try {
            Date expiresAt = new Date(System.currentTimeMillis()+EXPIRE_TIME);
            token = JWT.create()
                    .withIssuer("auth0")
                    .withClaim("userName",userName)
                    .withExpiresAt(expiresAt)
                    //使用HMAC256算法加密
                    .sign(Algorithm.HMAC256(TOKEN_SECRET));
        }catch (Exception e){
            e.printStackTrace();
        }
        return token;
    }

    /**
    * 签名验证
    * @param token
    * */
    public static boolean verify(String token){
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET))
                    .withIssuer("auth0").build();
            DecodedJWT jwt = verifier.verify(token);
            System.out.println("认证通过");
            System.out.println("userName:"+jwt.getClaim("userName").asString());
            System.out.println("过期时间:"+jwt.getExpiresAt());
            return true;
        }catch (Exception e){
            return false;
        }
    }

}
  • 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.