代码是抄来的,做个记录以后用 <!-- JWT依赖 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
package com.beef.shop.common.config; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Date; /** * JWT的token,区分大小写 */ @ConfigurationProperties(prefix = "config.jwt") @Component public class JwtConfig { private String secret; private long expire; private String header; /** * 生成token * @param subject * @return */ public String createToken (String subject){ Date nowDate = new Date(); Date expireDate = new Date(nowDate.getTime() + expire * 1000);//过期时间 return Jwts.builder() .setHeaderParam("typ", "JWT") .setSubject(subject) .setIssuedAt(nowDate) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } /** * 获取token中注册信息 * @param token * @return */ public Claims getTokenClaim (String token) { try { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); }catch (Exception e){ // e.printStackTrace(); return null; } } /** * 验证token是否过期失效 * @param expirationTime * @return */ public boolean isTokenExpired (Date expirationTime) { return expirationTime.before(new Date()); } /** * 获取token失效时间 * @param token * @return */ public Date getExpirationDateFromToken(String token) { return getTokenClaim(token).getExpiration(); } /** * 获取用户名从token中 */ public String getUsernameFromToken(String token) { return getTokenClaim(token).getSubject(); } /** * 获取jwt发布时间 */ public Date getIssuedAtDateFromToken(String token) { return getTokenClaim(token).getIssuedAt(); } // --------------------- getter & setter --------------------- public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } public long getExpire() { return expire; } public void setExpire(long expire) { this.expire = expire; } public String getHeader() { return header; } public void setHeader(String header) { this.header = header; } }
定义异常
package com.beef.shop.common.config; import com.beef.shop.common.utils.ReturnInfo; import com.beef.shop.common.utils.StatusInfo; import io.jsonwebtoken.SignatureException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class PermissionHandler { @ExceptionHandler(value = { SignatureException.class }) @ResponseBody public String authorizationException(SignatureException e){ return ReturnInfo.returnJsonInfo(StatusInfo.FAIL,"失败"); } }
配置token过滤器
package com.beef.shop.common.config; import io.jsonwebtoken.Claims; import io.jsonwebtoken.SignatureException; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class TokenInterceptor extends HandlerInterceptorAdapter { @Resource private JwtConfig jwtConfig ; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws SignatureException { /** 地址过滤 */ String uri = request.getRequestURI() ; if (uri.contains("/login")){ return true ; } /** Token 验证 */ String token = request.getHeader(jwtConfig.getHeader()); if(StringUtils.isEmpty(token)){ token = request.getParameter(jwtConfig.getHeader()); } if(StringUtils.isEmpty(token)){ throw new SignatureException(jwtConfig.getHeader()+ "不能为空"); } Claims claims = null; try{ claims = jwtConfig.getTokenClaim(token); if(claims == null || jwtConfig.isTokenExpired(claims.getExpiration())){ throw new SignatureException(jwtConfig.getHeader() + "失效,请重新登录。"); } }catch (Exception e){ throw new SignatureException(jwtConfig.getHeader() + "失效,请重新登录。"); } /** 设置 identityId 用户身份ID */ request.setAttribute("identityId", claims.getSubject()); return true; } } 注册拦截器
package com.beef.shop.common.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.Resource; @Configuration public class WebConfig implements WebMvcConfigurer { @Resource private TokenInterceptor tokenInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(tokenInterceptor).addPathPatterns("/**"); } }
登录验证
package com.beef.shop.controller; import com.alibaba.fastjson.JSONObject; import com.beef.shop.common.config.JwtConfig; import com.beef.shop.common.utils.ReturnInfo; import com.beef.shop.common.utils.StatusInfo; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @RestController public class TokenController { @Resource private JwtConfig jwtConfig ; /** * 用户登录接口 * @param userName * @param passWord * @return */ @PostMapping("/login") public String login (@RequestParam("userName") String userName, @RequestParam("passWord") String passWord){ JSONObject json = new JSONObject(); /** 验证userName,passWord和数据库中是否一致,如不一致,直接return ResultTool.errer(); 【这里省略该步骤】*/ // 这里模拟通过用户名和密码,从数据库查询userId // 这里把userId转为String类型,实际开发中如果subject需要存userId,则可以JwtConfig的createToken方法的参数设置为Long类型 String userId = 5 + "10011"; String token = jwtConfig.createToken(userId) ; if (!StringUtils.isEmpty(token)) { json.put("token",token) ; } return ReturnInfo.returnJsonInfo(StatusInfo.SUCCESS, json); } /** * 需要 Token 验证的接口 */ @PostMapping("/info") public String info (){ return ReturnInfo.returnJsonInfo(StatusInfo.SUCCESS, "info"); } /** * 根据请求头的token获取userId * @param request * @return */ @GetMapping("/getUserInfo") public String getUserInfo(HttpServletRequest request){ String usernameFromToken = jwtConfig.getUsernameFromToken(request.getHeader("token")); return ReturnInfo.returnJsonInfo(StatusInfo.SUCCESS, usernameFromToken); } /* 为什么项目重启后,带着之前的token还可以访问到需要info等需要token验证的接口? 答案:只要不过期,会一直存在,类似于redis */ }
spring.application.name=springboot-jwt # 加密密钥 config.jwt.secret= abcdefg1234567 # token有效时长 config.jwt.expire=3600 # header 名称 config.jwt.header=token
在postman调试post请求
http://localhost:9091/login?userName=zhangsan&passWord=123
{"result":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI1MTAwMTEiLCJpYXQiOjE2MDAzMjc5ODQsImV4cCI6MTYwMDMzMTU4NH0.r0vmHp1_N7sMI51UMvuApiB1O0Vzo9HOIzWyuUlOZUH6Sw9fzOG4sOQlv64GMlR_6dt8d526czclhel08fiUKQ"},"statusMsg":"成功","success":true,"unAuthorizedRequest":false,"statusCode":"200"}