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