这个是我工作中遇到的一个问题,因为之前没用过token,所以很陌生。不过好在我在网上一顿查,CSDN和度娘都快被我翻没了终于把他整出来了,现在来看一下代码。

首先先看一下我们用到得类有哪些。我们主要用到的是这几个类。

springboot antd 前后端分离项目实例 springboot前后端分离token_java

首先我们需要整一个TokenUtil的工具类

TokenUtil(工具类)

这里面的东西你基本上复制一下就可以不需要改什么东西,只需要改一下你的参数就可以了。

package com.wl.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.*;

/**
 * @author 小于小于, 一条咸鱼
 * @date 2022/6/17 13:37
 */
public class TokenUtil {

    /**
     * 过期时间为一个小时
     */
    private static final long EXPIRE_TIME =  60 * 60 * 1000;

    /**
     * token私钥  这里的密码随便写就可以
     */
    private static final String TOKEN_SECRET = "adm2345dfin234sdsdff";
    
    /**
    这里的参数根据你的需要来,因为我没有实体类,所以我在登录接口中写的假数据,这里你如果有实体类 
    的话你可以传一个User user
    */
    public static String createToken(String username,String password) {
       String token = null;
       Date expiration = new Date(System.currentTimeMillis() + EXPIRE_TIME);
       Map<String,Object> header = new HashMap<>();
       header.put("typ","JWT");
       header.put("alg","HS256");
       token = JWT.create()
               .withIssuer("auth0")
               .withHeader(header)
                //这个地方是你传的参数
               .withClaim("username",username)
               .withClaim("password",password)
               .withExpiresAt(expiration)
               .sign(Algorithm.HMAC256(TOKEN_SECRET));
       return 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("过期时间:" + jwt.getExpiresAt());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Token认证失败,需要重新登录!");
        }
        return false;
    }
}

接下来我们需要创建一个拦截器

创建拦截器(TokenInterceptor)

这里也不需要改很多东西直接,就是要改一下前端Vue的显示token的字段。

package com.wl.config;

import com.wl.util.TokenUtil;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 小于小于, 一条咸鱼
 * @date 2022/6/20 17:27
 */
@Component
@CrossOrigin
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");
    //这里是前端Vue放在请求头中的字段名   Authorization:token字符串
    String token = request.getHeader("Authorization");

    if (token != null){
        boolean flag = TokenUtil.verify(token);
        if (flag) {
            System.out.println("验证成功:"+ token);
            return true;
        }
    }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try{
            JSONObject json = new JSONObject();
            json.put("msg","token失效请重新登陆");
            json.put("code","50000");
            response.getWriter().append(json.toString());
            System.out.println("认证失败,未通过拦截器");

        }catch (Exception e){
            e.printStackTrace();
            response.sendError(500);
            return false;
        }
        return false;
    }
}

 配置跨域

这里的话也不需要改很多,只需要改一下你要拦截的路径即可,我是因为没有注册,我只把登录的接口给放出来了,其他的接口全部拦截。你可以根据的你的需要进行取舍,这里得线城池我是手动创建的,具体啥用我也没太搞懂,有没有这个应该是都可以的,你要嫌麻烦直接copy是没问题的。是

package com.wl.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
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;
import java.util.concurrent.*;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author 小于小于, 一条咸鱼
 * @date 2022/6/20 17:57
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    //最大30线程,外加30队列;【拒绝策略AbortPolicy(默认): 丢弃任务并抛出异常】
    private static ExecutorService executorService = new ThreadPoolExecutor
            (1, 30, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3));

    @Autowired
    private TokenInterceptor tokenInterceptor;


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedHeaders("*")
                .allowedMethods("*")
                .allowedOriginPatterns("*")
                .allowCredentials(true);
    }
    
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        configurer.setTaskExecutor(new ConcurrentTaskExecutor(executorService));
        configurer.setDefaultTimeout(30000);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        List<String> excludePath = new ArrayList<>();
        //排除拦截,除了注册登录(此时还没token),其他都拦截
        excludePath.add("/user/login");  //登录
        //excludePath.add("/login");     //注册
        //excludePath.add("/assets");  //静态资源
        //excludePath.add("/song/**");  //静态资源

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

}

 最后就是我们的登录接口了

LoginController

这里就很简单了,判断前端的账号密码是否正确,正确的话就创建Token然后保存在map中并返回给前端,如果不正确就给前端一个500的错误提示。

package com.wl.conrtoller;

import com.wl.util.TokenUtil;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 小于小于, 一条咸鱼
 * @date 2022/6/17 13:05
 */
@ResponseBody
@RestController
@CrossOrigin
@RequestMapping(value = "/user")
public class LoginController {



    /**
     * 登录
     *
     * @param
     * @return
     *      192.168.124.39:8081/user/login
     */

    @PostMapping("/login")
    public Object login(@RequestParam("username") String username,@RequestParam("password") String password){
       Map<String, Object> map = new HashMap<>();
       if ("admin".equals(username)&& "123456".equals(password)){
           //创建token并返回给前端。
           String token = TokenUtil.createToken(username, password);
           map.put("token",token);
           map.put("username",username);
           map.put("password",password);
           map.put("msg","登录成功");
           map.put("code",200);
       }else {
           map.put("msg","账号密码错误");
           map.put("code",500);
       }
            return map;
    }

}