diff --git a/README.md b/README.md index 3f08ac8..b552f5c 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,12 @@ 7、SpringBoot2.0 整合 Dubbo框架 ,实现RPC服务远程调用
- + 8、SpringBoot2.0 整合 ElasticSearch框架,实现高性能搜索引擎
+ +9、SpringBoot2.0 整合 JWT 框架,解决Token跨域验证问题
+ 持续更新中... ## 项目简介 diff --git a/pom.xml b/pom.xml index 5e5cb14..0d28f13 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,8 @@ ware-dubbo-parent ware-elastic-search + + ware-jwt-token diff --git a/ware-jwt-token/pom.xml b/ware-jwt-token/pom.xml new file mode 100644 index 0000000..80e2bb7 --- /dev/null +++ b/ware-jwt-token/pom.xml @@ -0,0 +1,48 @@ + + + + org.springframework.boot + spring-boot-starters + 2.1.3.RELEASE + + 4.0.0 + com.jwt.token + ware-jwt-token + jar + + + + org.springframework.boot + spring-boot-starter-web + + + io.jsonwebtoken + jjwt + 0.7.0 + + + + + + ${project.artifactId} + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/ware-jwt-token/src/main/java/com/jwt/token/JwtApplication.java b/ware-jwt-token/src/main/java/com/jwt/token/JwtApplication.java new file mode 100644 index 0000000..eb03f79 --- /dev/null +++ b/ware-jwt-token/src/main/java/com/jwt/token/JwtApplication.java @@ -0,0 +1,11 @@ +package com.jwt.token; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class JwtApplication { + public static void main(String[] args) { + SpringApplication.run(JwtApplication.class,args) ; + } +} diff --git a/ware-jwt-token/src/main/java/com/jwt/token/config/JwtConfig.java b/ware-jwt-token/src/main/java/com/jwt/token/config/JwtConfig.java new file mode 100644 index 0000000..54c82ea --- /dev/null +++ b/ware-jwt-token/src/main/java/com/jwt/token/config/JwtConfig.java @@ -0,0 +1,66 @@ +package com.jwt.token.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; + +@ConfigurationProperties(prefix = "config.jwt") +@Component +public class JwtConfig { + /* + * 根据身份ID标识,生成Token + */ + public String getToken (String identityId){ + Date nowDate = new Date(); + //过期时间 + Date expireDate = new Date(nowDate.getTime() + expire * 1000); + return Jwts.builder() + .setHeaderParam("typ", "JWT") + .setSubject(identityId) + .setIssuedAt(nowDate) + .setExpiration(expireDate) + .signWith(SignatureAlgorithm.HS512, secret) + .compact(); + } + /* + * 获取 Token 中注册信息 + */ + public Claims getTokenClaim (String token) { + try { + return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + }catch (Exception e){ + e.printStackTrace(); + return null; + } + } + /* + * Token 是否过期验证 + */ + public boolean isTokenExpired (Date expirationTime) { + return expirationTime.before(new Date()); + } + private String secret; + private long expire; + private String header; + 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; + } +} diff --git a/ware-jwt-token/src/main/java/com/jwt/token/config/WebConfig.java b/ware-jwt-token/src/main/java/com/jwt/token/config/WebConfig.java new file mode 100644 index 0000000..27e6e20 --- /dev/null +++ b/ware-jwt-token/src/main/java/com/jwt/token/config/WebConfig.java @@ -0,0 +1,20 @@ +package com.jwt.token.config; + +import com.jwt.token.interceptor.TokenInterceptor; +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 ; + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(tokenInterceptor).addPathPatterns("/**"); + } +} diff --git a/ware-jwt-token/src/main/java/com/jwt/token/controller/TokenController.java b/ware-jwt-token/src/main/java/com/jwt/token/controller/TokenController.java new file mode 100644 index 0000000..4091d76 --- /dev/null +++ b/ware-jwt-token/src/main/java/com/jwt/token/controller/TokenController.java @@ -0,0 +1,44 @@ +package com.jwt.token.controller; + +import com.jwt.token.config.JwtConfig; +import org.springframework.util.StringUtils; +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 java.util.HashMap; +import java.util.Map; + +@RestController +public class TokenController { + @Resource + private JwtConfig jwtConfig ; + /* + * 返参格式 + * { + * "userName": "ID123", + * "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9. + * eyJzdWIiOiJJRDEyM3B3MTIzIiwiaWF0Ijox. + * SqqaZfG_g2OMijyN5eG0bPmkIQaqMRFlUvny" + * } + */ + // 拦截器直接放行,返回Token + @PostMapping("/login") + public Map login (@RequestParam("userName") String userName, + @RequestParam("passWord") String passWord){ + Map result = new HashMap<>() ; + // 省略数据源校验 + String token = jwtConfig.getToken(userName+passWord) ; + if (!StringUtils.isEmpty(token)) { + result.put("token",token) ; + } + result.put("userName",userName) ; + return result ; + } + // 需要 Token 验证的接口 + @PostMapping("/info") + public String info (){ + return "info" ; + } +} diff --git a/ware-jwt-token/src/main/java/com/jwt/token/interceptor/TokenInterceptor.java b/ware-jwt-token/src/main/java/com/jwt/token/interceptor/TokenInterceptor.java new file mode 100644 index 0000000..58f6664 --- /dev/null +++ b/ware-jwt-token/src/main/java/com/jwt/token/interceptor/TokenInterceptor.java @@ -0,0 +1,44 @@ +package com.jwt.token.interceptor; + +import com.jwt.token.config.JwtConfig; +import io.jsonwebtoken.Claims; +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; + +/** + * Token 拦截器 + */ +@Component +public class TokenInterceptor extends HandlerInterceptorAdapter { + @Resource + private JwtConfig jwtConfig ; + @Override + public boolean preHandle(HttpServletRequest request, + HttpServletResponse response, + Object handler) throws Exception { + // 地址过滤 + 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 Exception(jwtConfig.getHeader()+ "不能为空"); + } + Claims claims = jwtConfig.getTokenClaim(token); + if(claims == null || jwtConfig.isTokenExpired(claims.getExpiration())){ + throw new Exception(jwtConfig.getHeader() + "失效,请重新登录"); + } + //设置 identityId 用户身份ID + request.setAttribute("identityId", claims.getSubject()); + return true; + } +} diff --git a/ware-jwt-token/src/main/resources/application.yml b/ware-jwt-token/src/main/resources/application.yml new file mode 100644 index 0000000..5816469 --- /dev/null +++ b/ware-jwt-token/src/main/resources/application.yml @@ -0,0 +1,13 @@ +server: + port: 7009 +spring: + application: + name: ware-jwt-token +config: + jwt: + # 加密密钥 + secret: iwqjhda8232bjgh432[cicada-smile] + # token有效时长 + expire: 3600 + # header 名称 + header: token \ No newline at end of file