Token
流程: 1.建立token工具类,先编辑token签名sign():设置超时时长、token秘钥。 2.配置拦截器类,拦截器中重写preHandle()方法,对每次请求进行自定义的拦截操作。 3.建立配置类:定义拦截与不拦截的接口信息。
页面请求登录接口→登录成功后,返回登录信息+token秘钥给前端→前端记住密钥信息,并赋予每个接口(例:在每个接口访问时将秘钥信息放置于headers中的参数下)→拦截器接到请求,从headers获取token密钥进行匹配,通过则继续访问,不通过则返回提示信息。
1..建立token工具类,先编辑token签名sign():设置超时时长、token秘钥。
import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import lombok.extern.slf4j.Slf4j; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.HashMap; import java.util.Map; @Slf4j public class JwtUtil { /** * 过期时间 */ private static final long EXPIRE_TIME = 15 * 60 * 1000; /** * token秘钥 */ private static final String TOKEN_SECRET = "c369a1e4-43ee-4e1e-b130-2b952f1ba9ad"; /** * 签名方法 * @Param userName userName * @Param role role * @return String role */ public static String sign(String userName, String role) { log.info("sign begin."); try { // 过期时间 Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); // 秘钥和加密算法 Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); // headers Map<String, Object> herders = new HashMap<>(2); herders.put("typ", "JWT"); herders.put("alg", "HS256"); log.info("sign end."); return JWT.create() .withHeader(herders) .withClaim("userName", userName) .withClaim("role", role) .withExpiresAt(date) .sign(algorithm); } catch (UnsupportedEncodingException exception) { exception.printStackTrace(); log.info("sign error."); return exception.getMessage(); } } /** * token 校验方法 * @Param userName userName * @return String role */ public static boolean verify(String token) { log.info("verify begin."); try { Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); JWTVerifier verifier = JWT.require(algorithm).build(); verifier.verify(token); log.info("verify end."); return true; } catch (UnsupportedEncodingException exception) { log.info("verify error."); exception.printStackTrace(); return false; } } }
2.controller层登录操作中设置登录校验及token插入:
/** * @program: smartOperationTest * @description: 用户操作 * @author: 作者名字 * @create: 2021-07-15 10:37 **/ @Controller @RequestMapping("/user") @Api("userActionController") @CrossOrigin(value = "*", maxAge = 3600) @Slf4j public class UserActionController { @Autowired UserInfoServiceImpl userInfoService; @RequestMapping(value = "/login", method = RequestMethod.GET) @ApiOperation(value = "登录", notes = "") @ResponseBody public CommonResultBO userLogin(@RequestParam() String username, @RequestParam() String password) { CommonResultBO resultBO = userInfoService.getUserInfo(username, password); Integer statusCode = resultBO.getStatusCode(); if (statusCode == 200) {// 登录校验通过则插入token信息 UserInfo userInfo = (UserInfo)resultBO.getData(); String token = JwtUtil.sign(username, userInfo.getRole()); resultBO.setData(token); return resultBO; } resultBO.setData(""); resultBO.setStatusCode(1); resultBO.setStatusMessage("token failed"); return resultBO; } }
3.设置拦截器
import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @program: smartOperationTest * @description: 拦截器 * @author: 作者名字 * @create: 2021-07-15 16:20 **/ @Component @Slf4j public class TokenInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws IOException { log.info("preHandle begin."); response.setCharacterEncoding("utf-8"); String token = request.getHeader("accessToken"); log.info("preHandle begin TOKEN: {}." + token); // token通过验证 返回true 继续访问 if (null != token) { boolean result = JwtUtil.verify(token) ; if (result) { log.info("preHandle end."); return true; } } // token验证不通过 返回失败提示 CommonResultBO commonResultBO = CommonResultBO.init(null, -1, "failed", "token invalid"); response.getWriter().write(JSONObject.toJSONString(commonResultBO)); log.info("preHandle end."); return false; } }
4.建立配置类,明确拦截与不拦截的接口:/*拦截一层路径,/**拦截/后全布路径。
import com.hawk.smartoperationtest.common.TokenInterceptor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.*; /** * @program: smartOperationTest * @description: 自定义拦截器配置 * @author: 作者名字 * @create: 2021-07-15 16:48 **/ @Configuration @Slf4j public class MvcConfig extends WebMvcConfigurationSupport { @Autowired TokenInterceptor tokenInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { //添加自定义拦截器 log.info("addInterceptors begin."); InterceptorRegistration patterns = registry.addInterceptor(tokenInterceptor).addPathPatterns("/mary/**") //指定拦截的url地址 .excludePathPatterns("/user/**", "/swagger-resources/**", "/v2/**"); log.info("addInterceptors :" + patterns.toString()); } /** * 发现如果继承了WebMvcConfigurationSupport,则在yml中配置的相关内容会失效。 * 配置拦截器后swagger访问会被拦截 按如下配置可保持swagger访问 * 需要重新指定静态资源 * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); registry.addResourceHandler("swagger-ui.html") .addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/"); // super.addResourceHandlers(registry); } }
登录验证通过后,再次进行接口访问时,header中就要携带token信息进行校验。例:
accessToken:xxxtoken加密信息xxxx
verify()也可以用于任意地方进行token校验。
解析token:例
DecodedJWT verify = verifier.verify(token); String role = verify.getClaim("role").asString();