28 changed files with 321 additions and 19 deletions
@ -0,0 +1,12 @@ |
|||||
|
package com.zdxt.knowledge.annotation; |
||||
|
|
||||
|
import java.lang.annotation.ElementType; |
||||
|
import java.lang.annotation.Retention; |
||||
|
import java.lang.annotation.RetentionPolicy; |
||||
|
import java.lang.annotation.Target; |
||||
|
|
||||
|
@Target(ElementType.METHOD) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
public @interface Applet { |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
package com.zdxt.knowledge.jwt; |
||||
|
|
||||
|
public class JwtClaimsConstant { |
||||
|
|
||||
|
public static final String USER_ID = "JWT_CLAIMS_USER_IDENTITY"; |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
package com.zdxt.knowledge.jwt; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "wechat.jwt") |
||||
|
@Data |
||||
|
public class JwtProperties { |
||||
|
/** |
||||
|
* 用户端微信用户生成jwt令牌相关配置 |
||||
|
*/ |
||||
|
private String userSecretKey; |
||||
|
private long userTtl; |
||||
|
private String userTokenName; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
@ -0,0 +1,76 @@ |
|||||
|
package com.zdxt.knowledge.jwt; |
||||
|
|
||||
|
import com.zdxt.knowledge.annotation.Applet; |
||||
|
import com.zdxt.knowledge.domain.WechatUser; |
||||
|
import com.zdxt.knowledge.mapper.WechatLoginMapper; |
||||
|
import io.jsonwebtoken.Claims; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.web.method.HandlerMethod; |
||||
|
import org.springframework.web.servlet.HandlerInterceptor; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.util.Objects; |
||||
|
|
||||
|
/** |
||||
|
* jwt令牌校验的拦截器 |
||||
|
*/ |
||||
|
@Component |
||||
|
@Slf4j |
||||
|
public class JwtTokenUserInterceptor implements HandlerInterceptor { |
||||
|
|
||||
|
@Autowired |
||||
|
private JwtProperties jwtProperties; |
||||
|
|
||||
|
@Autowired |
||||
|
private WechatLoginMapper wechatLoginMapper; |
||||
|
|
||||
|
/** |
||||
|
* 校验jwt |
||||
|
* |
||||
|
* @param request |
||||
|
* @param response |
||||
|
* @param handler |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
*/ |
||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
||||
|
|
||||
|
//判断当前拦截到的是Controller的方法还是其他资源
|
||||
|
if (!(handler instanceof HandlerMethod)) { |
||||
|
//当前拦截到的不是动态方法,直接放行
|
||||
|
return true; |
||||
|
} |
||||
|
//只校验小程序的接口,如果不是小程序调用的接口放行
|
||||
|
Applet annotation = ((HandlerMethod) handler) |
||||
|
.getMethodAnnotation(Applet.class); |
||||
|
|
||||
|
if (annotation == null) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
//1、从请求头中获取令牌
|
||||
|
String token = request.getHeader(jwtProperties.getUserTokenName()); |
||||
|
|
||||
|
//2、校验令牌
|
||||
|
try { |
||||
|
log.info("jwt校验:{}", token); |
||||
|
Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token); |
||||
|
String userId = claims.get(JwtClaimsConstant.USER_ID).toString(); |
||||
|
log.info("当前用户id:", userId); |
||||
|
WechatUser wechatUser = wechatLoginMapper.selectUserById(userId); |
||||
|
if (Objects.nonNull(wechatUser)) { |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} catch (Exception ex) { |
||||
|
//4、不通过,响应401状态码
|
||||
|
response.setStatus(401); |
||||
|
throw new RuntimeException("非法调用"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
@ -0,0 +1,59 @@ |
|||||
|
package com.zdxt.knowledge.jwt; |
||||
|
|
||||
|
import io.jsonwebtoken.Claims; |
||||
|
import io.jsonwebtoken.JwtBuilder; |
||||
|
import io.jsonwebtoken.Jwts; |
||||
|
import io.jsonwebtoken.SignatureAlgorithm; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.util.Date; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
public class JwtUtil { |
||||
|
/** |
||||
|
* 生成jwt |
||||
|
* 使用Hs256算法, 私匙使用固定秘钥 |
||||
|
* |
||||
|
* @param secretKey jwt秘钥 |
||||
|
* @param ttlMillis jwt过期时间(毫秒) |
||||
|
* @param claims 设置的信息 |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) { |
||||
|
// 指定签名的时候使用的签名算法,也就是header那部分
|
||||
|
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; |
||||
|
|
||||
|
// 生成JWT的时间
|
||||
|
long expMillis = System.currentTimeMillis() + ttlMillis; |
||||
|
Date exp = new Date(expMillis); |
||||
|
|
||||
|
// 设置jwt的body
|
||||
|
JwtBuilder builder = Jwts.builder() |
||||
|
// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
|
||||
|
.setClaims(claims) |
||||
|
// 设置签名使用的签名算法和签名使用的秘钥
|
||||
|
.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8)) |
||||
|
// 设置过期时间
|
||||
|
.setExpiration(exp); |
||||
|
|
||||
|
return builder.compact(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Token解密 |
||||
|
* |
||||
|
* @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个 |
||||
|
* @param token 加密后的token |
||||
|
* @return |
||||
|
*/ |
||||
|
public static Claims parseJWT(String secretKey, String token) { |
||||
|
// 得到DefaultJwtParser
|
||||
|
Claims claims = Jwts.parser() |
||||
|
// 设置签名的秘钥
|
||||
|
.setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8)) |
||||
|
// 设置需要解析的jwt
|
||||
|
.parseClaimsJws(token).getBody(); |
||||
|
return claims; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
@ -0,0 +1,39 @@ |
|||||
|
package com.zdxt.knowledge.jwt; |
||||
|
|
||||
|
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.InterceptorRegistry; |
||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; |
||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||
|
|
||||
|
/** |
||||
|
* 配置类,注册web层相关组件 |
||||
|
*/ |
||||
|
@Configuration |
||||
|
@Slf4j |
||||
|
public class WebMvcConfiguration implements WebMvcConfigurer { |
||||
|
|
||||
|
@Autowired |
||||
|
private JwtTokenUserInterceptor jwtTokenUserInterceptor; |
||||
|
|
||||
|
@Override |
||||
|
public void addInterceptors(InterceptorRegistry registry) { |
||||
|
registry.addInterceptor(new JwtTokenUserInterceptor()) |
||||
|
.addPathPatterns("/small/**") |
||||
|
.excludePathPatterns("/small/wechat/login"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) { |
||||
|
registry.addResourceHandler("/**") |
||||
|
.addResourceLocations("classpath:/") |
||||
|
.addResourceLocations("classpath:/static/") |
||||
|
.addResourceLocations("classpath:/config/") |
||||
|
.addResourceLocations("classpath:/excel/") |
||||
|
.addResourceLocations("classpath:/font/") |
||||
|
.addResourceLocations("classpath:/template/") |
||||
|
.addResourceLocations("classpath:/templates/"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
Loading…
Reference in new issue