From 2b988de5607abf53c7587c8870b8bf76da315797 Mon Sep 17 00:00:00 2001 From: wxz Date: Wed, 23 Sep 2020 14:33:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=86=85=E9=83=A8=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E8=AE=A4=E8=AF=81=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../epmet-commons-extapp-auth/pom.xml | 6 + .../annotation/InternalAppRequestAuth.java | 32 +++++ .../aspect/ExternalAppRequestAuthAspect.java | 117 +++++++++++++++- .../extappauth/jwt/JwtTokenProperties.java | 41 ++++++ .../commons/extappauth/jwt/JwtTokenUtils.java | 130 ++++++++++++++++++ .../tools/exception/EpmetErrorCode.java | 2 +- .../epmet/controller/test/TestController.java | 19 --- 7 files changed, 325 insertions(+), 22 deletions(-) create mode 100644 epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/annotation/InternalAppRequestAuth.java create mode 100644 epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/jwt/JwtTokenProperties.java create mode 100644 epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/jwt/JwtTokenUtils.java delete mode 100644 epmet-module/data-report/data-report-server/src/main/java/com/epmet/controller/test/TestController.java diff --git a/epmet-commons/epmet-commons-extapp-auth/pom.xml b/epmet-commons/epmet-commons-extapp-auth/pom.xml index de7060d57f..b563afcb7d 100644 --- a/epmet-commons/epmet-commons-extapp-auth/pom.xml +++ b/epmet-commons/epmet-commons-extapp-auth/pom.xml @@ -27,6 +27,12 @@ + + io.jsonwebtoken + jjwt + 0.7.0 + + org.springframework.boot spring-boot-starter-web diff --git a/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/annotation/InternalAppRequestAuth.java b/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/annotation/InternalAppRequestAuth.java new file mode 100644 index 0000000000..921860627c --- /dev/null +++ b/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/annotation/InternalAppRequestAuth.java @@ -0,0 +1,32 @@ +/** + * Copyright 2018 人人开源 http://www.renren.io + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.epmet.commons.extappauth.annotation; + +import java.lang.annotation.*; + +/** + * 需要认证的内部请求 + * @Author wxz + * @Description + * @Date 2020/4/23 16:17 + **/ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface InternalAppRequestAuth { + +} diff --git a/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/aspect/ExternalAppRequestAuthAspect.java b/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/aspect/ExternalAppRequestAuthAspect.java index ec98b35d7b..c9b252c0ca 100644 --- a/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/aspect/ExternalAppRequestAuthAspect.java +++ b/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/aspect/ExternalAppRequestAuthAspect.java @@ -1,13 +1,23 @@ package com.epmet.commons.extappauth.aspect; +import cn.hutool.core.bean.BeanUtil; +import com.epmet.commons.extappauth.annotation.ExternalAppRequestAuth; +import com.epmet.commons.extappauth.annotation.InternalAppRequestAuth; import com.epmet.commons.extappauth.bean.ExternalAppRequestParam; +import com.epmet.commons.extappauth.jwt.JwtTokenUtils; import com.epmet.commons.tools.exception.EpmetErrorCode; import com.epmet.commons.tools.exception.RenException; +import com.epmet.commons.tools.redis.RedisKeys; +import com.epmet.commons.tools.redis.RedisUtils; +import com.epmet.commons.tools.security.dto.BaseTokenDto; +import com.epmet.commons.tools.security.dto.GovTokenDto; +import com.epmet.commons.tools.security.dto.TokenDto; import com.epmet.commons.tools.utils.Result; import com.epmet.dto.form.ExternalAppAuthFormDTO; import com.epmet.dto.result.ExternalAppAuthResultDTO; import com.epmet.feign.EpmetCommonServiceOpenFeignClient; +import io.jsonwebtoken.Claims; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; @@ -24,6 +34,7 @@ import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Parameter; +import java.util.Map; /** * 外部应用请求认证切面 @@ -35,6 +46,7 @@ public class ExternalAppRequestAuthAspect { private static Logger logger = LoggerFactory.getLogger(ExternalAppRequestAuthAspect.class); + public static final String AUTHORIZATION_TOKEN_HEADER_KEY = "Authorization"; public static final String ACCESS_TOKEN_HEADER_KEY = "AccessToken"; public static final String APP_ID_HEADER_KEY = "appId"; public static final String APP_ID_TIMESTAMP_KEY = "ts"; @@ -44,15 +56,117 @@ public class ExternalAppRequestAuthAspect { @Autowired private EpmetCommonServiceOpenFeignClient commonServiceOpenFeignClient; + @Autowired + private JwtTokenUtils jwtTokenUtils; + + @Autowired + private RedisUtils redisUtils; + /** * 拦截加了ExternalRequestAuth注解的方法 * * @param point * @throws Throwable */ - @Before("@annotation(com.epmet.commons.extappauth.annotation.ExternalAppRequestAuth)") + @Before("@annotation(com.epmet.commons.extappauth.annotation.ExternalAppRequestAuth) " + + "|| @annotation(com.epmet.commons.extappauth.annotation.InternalAppRequestAuth)") public void auth(JoinPoint point) throws Throwable { + MethodSignature signature = (MethodSignature) point.getSignature(); HttpServletRequest request = getRequest(); + + if (signature.getMethod().getAnnotation(ExternalAppRequestAuth.class) != null + && StringUtils.isNotBlank(request.getHeader(ACCESS_TOKEN_HEADER_KEY))) { + // 走外部应用认证 + extAppAuth(signature, point, request); + } else if (signature.getMethod().getAnnotation(InternalAppRequestAuth.class) != null + && StringUtils.isNotBlank(request.getHeader(AUTHORIZATION_TOKEN_HEADER_KEY))) { + // 走内部应用认证 + String customerId = null; + internalAppAuth(signature, point, request); + } else { + throw new RenException(EpmetErrorCode.UNSUPPORT_AUTH_TYPE.getCode(), EpmetErrorCode.UNSUPPORT_AUTH_TYPE.getMsg()); + } + } + + /** + * 内部应用认证 + * @param signature + * @param point + * @param request + * @return + */ + private void internalAppAuth(MethodSignature signature, JoinPoint point, HttpServletRequest request) { + String authorization = request.getHeader(AUTHORIZATION_TOKEN_HEADER_KEY); + BaseTokenDto tokenDTO = getTokenDTO(authorization); + + Map tokenMap = redisUtils.hGetAll(RedisKeys.getCpUserKey(tokenDTO.getApp(), tokenDTO.getClient(), tokenDTO.getUserId())); + BaseTokenDto baseTokenDto = null; + String customerId; + if ("gov".equals(tokenDTO.getApp())) { + GovTokenDto govTokenDto = BeanUtil.mapToBean(tokenMap, GovTokenDto.class, true); + customerId = govTokenDto.getCustomerId(); + baseTokenDto = govTokenDto; + } else { + TokenDto tokenDto = BeanUtil.mapToBean(tokenMap, TokenDto.class, true); + customerId = tokenDto.getCustomerId(); + baseTokenDto = tokenDTO; + } + + if (baseTokenDto == null) { + logger.error("内部应用认证,redis中没有找到登录缓存信息"); + throw new RenException(EpmetErrorCode.ERR10006.getCode(), EpmetErrorCode.ERR10006.getMsg()); + } + + if (!authorization.equals(baseTokenDto.getToken())) { + logger.error("内部应用认证,redis中找到的token与header里面传入的不一致,可能发生了别处登录"); + throw new RenException(EpmetErrorCode.ERR10007.getCode(), EpmetErrorCode.ERR10007.getMsg()); + } + + // header参数赋值 + Parameter[] parameters = signature.getMethod().getParameters(); + if (parameters != null && parameters.length != 0) { + for (int i = 0; i < parameters.length; i++) { + if (parameters[i].getType() == ExternalAppRequestParam.class) { + ExternalAppRequestParam requestParam = (ExternalAppRequestParam) point.getArgs()[i]; + requestParam.setCustomerId(customerId); + } + } + } + + } + + private BaseTokenDto getTokenDTO(String authorization) { + if (StringUtils.isBlank(authorization)) { + logger.error("内部应用认证,没有携带authorization头信息"); + throw new RenException(EpmetErrorCode.ERR401.getCode(), EpmetErrorCode.ERR401.getMsg()); + } + + //是否过期 + Claims claims = jwtTokenUtils.getClaimByToken(authorization); + if (claims == null) { + logger.error("内部应用认证,Claims为空"); + throw new RenException(EpmetErrorCode.ERR401.getCode(), EpmetErrorCode.ERR401.getMsg()); + } + + if (jwtTokenUtils.isTokenExpired(claims.getExpiration())) { + logger.error("内部应用认证,token过期"); + throw new RenException(EpmetErrorCode.ERR10006.getCode(), EpmetErrorCode.ERR10006.getMsg()); + } + + //获取用户ID + String app = (String) claims.get("app"); + String client = (String) claims.get("client"); + String userId = (String) claims.get("userId"); + return new BaseTokenDto(app, client, userId, authorization); + } + + /** + * 外部应用认证 + * + * @param signature + * @param point + */ + public void extAppAuth(MethodSignature signature, JoinPoint point, HttpServletRequest request) { String token = request.getHeader(ACCESS_TOKEN_HEADER_KEY); String appId = request.getHeader(APP_ID_HEADER_KEY); String ts = request.getHeader(APP_ID_TIMESTAMP_KEY); @@ -89,7 +203,6 @@ public class ExternalAppRequestAuthAspect { // header参数赋值 - MethodSignature signature = (MethodSignature) point.getSignature(); Parameter[] parameters = signature.getMethod().getParameters(); if (parameters != null && parameters.length != 0) { for (int i = 0; i < parameters.length; i++) { diff --git a/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/jwt/JwtTokenProperties.java b/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/jwt/JwtTokenProperties.java new file mode 100644 index 0000000000..8c7dcc2636 --- /dev/null +++ b/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/jwt/JwtTokenProperties.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2018 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.epmet.commons.extappauth.jwt; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * Jwt + * + * @author Mark sunlightcs@gmail.com + * @since 1.0.0 + */ +@Configuration +@ConfigurationProperties(prefix = "jwt.token") +public class JwtTokenProperties { + private String secret; + private int expire; + + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + public int getExpire() { + return expire; + } + + public void setExpire(int expire) { + this.expire = expire; + } +} diff --git a/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/jwt/JwtTokenUtils.java b/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/jwt/JwtTokenUtils.java new file mode 100644 index 0000000000..bd5eff1beb --- /dev/null +++ b/epmet-commons/epmet-commons-extapp-auth/src/main/java/com/epmet/commons/extappauth/jwt/JwtTokenUtils.java @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2018 人人开源 All rights reserved. + *

+ * https://www.renren.io + *

+ * 版权所有,侵权必究! + */ + +package com.epmet.commons.extappauth.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Jwt工具类 + * + * @author Mark sunlightcs@gmail.com + * @since 1.0.0 + */ +@Component +public class JwtTokenUtils { + private static final Logger logger = LoggerFactory.getLogger(JwtTokenUtils.class); + + @Autowired + private JwtTokenProperties jwtProperties; + + /** + * 生成jwt token 弃用 + */ + @Deprecated + public String generateToken(String userId) { + return Jwts.builder() + .setHeaderParam("typ", "JWT") + .setSubject(userId) + .setIssuedAt(new Date()) + .setExpiration(DateTime.now().plusSeconds(jwtProperties.getExpire()).toDate()) + .signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret()) + .compact(); + } + + public Claims getClaimByToken(String token) { + try { + return Jwts.parser() + .setSigningKey(jwtProperties.getSecret()) + .parseClaimsJws(token) + .getBody(); + } catch (Exception e) { + logger.debug("validate is token error, token = " + token, e); + return null; + } + } + + /** + * @return java.util.Date + * @param token + * @Author yinzuomei + * @Description 获取token的有效期截止时间 + * @Date 2020/3/18 22:17 + **/ + public Date getExpiration(String token){ + try { + return Jwts.parser() + .setSigningKey(jwtProperties.getSecret()) + .parseClaimsJws(token) + .getBody().getExpiration(); + } catch (Exception e) { + logger.debug("validate is token error, token = " + token, e); + return null; + } + } + + /** + * @param map + * @return java.lang.String + * @Author yinzuomei + * @Description 根据app+client+userId生成token + * @Date 2020/3/18 22:29 + **/ + public String createToken(Map map) { + return Jwts.builder() + .setHeaderParam("typ", "JWT") + .setClaims(map) + .setIssuedAt(new Date()) + .setExpiration(DateTime.now().plusSeconds(jwtProperties.getExpire()).toDate()) + .signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret()) + .compact(); + } + + /** + * token是否过期 + * + * @return true:过期 + */ + public boolean isTokenExpired(Date expiration) { + return expiration.before(new Date()); + } + + public static void main(String[] args) { + Map map=new HashMap<>(); + map.put("app","gov"); + map.put("client","wxmp"); + map.put("userId","100526ABC"); + String tokenStr=Jwts.builder() + .setHeaderParam("typ", "JWT") + .setClaims(map) + .setIssuedAt(new Date()) + .setExpiration(DateTime.now().plusSeconds(604800).toDate()) + .signWith(SignatureAlgorithm.HS512, "7016867071f0ebf1c46f123eaaf4b9d6[elink.epmet]") + .compact(); + System.out.println(tokenStr); + Claims claims= Jwts.parser() + .setSigningKey("7016867071f0ebf1c46f123eaaf4b9d6[elink.epmet]") + .parseClaimsJws(tokenStr) + .getBody(); + System.out.println("app="+ claims.get("app")); + System.out.println("client="+ claims.get("client")); + System.out.println("userId="+ claims.get("userId")); + } + +} diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java index 20a0b534f6..3417d172d8 100644 --- a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java +++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java @@ -95,7 +95,6 @@ public enum EpmetErrorCode { SIGN_IN_TIME_NO(8513, "签到时间还未到~"), SIGN_IN_TIME_END(8514, "签到时间已结束~"), - // 该错误不会提示给前端,只是后端传输错误信息用。 ACCESS_SQL_FILTER_MISSION_ARGS(8701, "缺少生成权限过滤SQL所需参数"), OPER_ADD_CUSTOMER_ROOT_AGENCY_ERROR(8702, "添加客户根级组织失败"), OPER_ADD_CUSTOMER_ROOT_AGENCY_EXISTS(8703, "添加客户根级组织失败,根级组织已存在"), @@ -108,6 +107,7 @@ public enum EpmetErrorCode { OPER_EXTERNAL_CUSTOMER_NOT_EXISTS(8710, "该客户不存在"), OPER_EXTERNAL_APP_EXISTS(8711, "应用已存在"), OPER_EXT_APP_SECRET_RESET_FAIL(8713, "秘钥更新失败"), + UNSUPPORT_AUTH_TYPE(8714, "不支持的认证方式"), // 党建声音 前端提示 88段 DRAFT_CONTENT_IS_NULL(8801, "至少需要添加一个段落"), diff --git a/epmet-module/data-report/data-report-server/src/main/java/com/epmet/controller/test/TestController.java b/epmet-module/data-report/data-report-server/src/main/java/com/epmet/controller/test/TestController.java deleted file mode 100644 index a16df89c2a..0000000000 --- a/epmet-module/data-report/data-report-server/src/main/java/com/epmet/controller/test/TestController.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.epmet.controller.test; - -import com.epmet.commons.extappauth.annotation.ExternalAppRequestAuth; -import com.epmet.commons.extappauth.bean.ExternalAppRequestParam; -import com.epmet.commons.tools.utils.Result; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("test") -public class TestController { - - @ExternalAppRequestAuth - @RequestMapping("/test") - public Result test(ExternalAppRequestParam externalAppRequestParam, String ext) { - return new Result().ok("调用成功,客户信息:"+externalAppRequestParam); - } - -}