Althars123 vor 3 Jahren
Ursprung
Commit
e0d9f38c93

+ 28 - 0
jkt-admin/src/main/java/com/miaxis/system/controller/system/SysLoginController.java

@@ -1,6 +1,7 @@
 package com.miaxis.system.controller.system;
 
 import com.alibaba.fastjson.JSONObject;
+import com.miaxis.apple.service.IAppleService;
 import com.miaxis.common.core.domain.Response;
 import com.miaxis.common.core.domain.entity.SysMenu;
 import com.miaxis.common.core.domain.entity.SysUser;
@@ -9,12 +10,14 @@ import com.miaxis.common.core.domain.model.LoginBodyNoCode;
 import com.miaxis.common.core.domain.model.LoginUser;
 import com.miaxis.common.enums.StudentLoginTypeEnum;
 import com.miaxis.common.exception.CustomException;
+import com.miaxis.common.utils.AppleUtil;
 import com.miaxis.common.utils.SecurityUtils;
 import com.miaxis.common.utils.ServletUtils;
 import com.miaxis.framework.web.service.SysLoginService;
 import com.miaxis.framework.web.service.SysPermissionService;
 import com.miaxis.framework.web.service.TokenService;
 import com.miaxis.system.dto.common.RouterDTO;
+import com.miaxis.system.dto.system.AppleTokenDTO;
 import com.miaxis.system.dto.system.TokenDTO;
 import com.miaxis.system.dto.system.UserInfoDTO;
 import com.miaxis.system.service.ISysMenuService;
@@ -31,7 +34,11 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -55,6 +62,9 @@ public class SysLoginController
     @Autowired
     private TokenService tokenService;
 
+    @Resource
+    private IAppleService appleService;
+
 
     @Autowired
     private WxService wxService;
@@ -143,6 +153,24 @@ public class SysLoginController
 
 
 
+    }
+
+    @PostMapping("/login/code/ios")
+    @ApiOperation("IOS登录")
+    public Response<AppleTokenDTO> ioslogin(String identityToken){
+        try {
+            JSONObject appleUser = appleService.getAppleUserInfo(identityToken);
+            String token = loginService.login(appleUser.getString("sub"),null, StudentLoginTypeEnum.AUTHORIZATION_CODE_LOGIN.getCode());
+            AppleTokenDTO tokenDTO = new AppleTokenDTO();
+            tokenDTO.setAppleUserInfo(appleUser);
+            tokenDTO.setToken(token);
+            return Response.success(tokenDTO);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new CustomException("获取苹果用户信息失败");
+        }
+
+
     }
 
 //

+ 12 - 0
jkt-common/pom.xml

@@ -169,6 +169,18 @@
             </exclusions>
         </dependency>
 
+        <!--IOS登录-->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>jwks-rsa</artifactId>
+            <version>0.9.0</version>
+        </dependency>
+
         <!--<dependency>-->
             <!--<groupId>com.tencentcloudapi</groupId>-->
             <!--<artifactId>tencentcloud-sdk-java</artifactId>-->

+ 17 - 0
jkt-common/src/main/java/com/miaxis/common/core/domain/model/AppleResult.java

@@ -0,0 +1,17 @@
+package com.miaxis.common.core.domain.model;
+
+
+import lombok.Data;
+
+@Data
+public class AppleResult {
+     String openid;
+     String access_token;
+     String refresh_token;
+     Integer expire_in;
+     String scope;
+     String unionid;
+     String errcode;
+     String errmsg;
+
+}

+ 106 - 0
jkt-common/src/main/java/com/miaxis/common/utils/AppleUtil.java

@@ -0,0 +1,106 @@
+package com.miaxis.common.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.auth0.jwk.Jwk;
+import io.jsonwebtoken.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.client.RestTemplate;
+
+import java.security.PublicKey;
+
+public class AppleUtil {
+
+    private static final Logger logger = LoggerFactory.getLogger(AppleUtil.class);
+    /**
+     * 获取苹果的公钥
+     * @return
+     * @throws Exception
+     */
+    private static JSONArray getAuthKeys() throws Exception {
+        String url = "https://appleid.apple.com/auth/keys";
+        RestTemplate restTemplate = new RestTemplate();
+        JSONObject json = restTemplate.getForObject(url,JSONObject.class);
+        JSONArray arr = json.getJSONArray("keys");
+        return arr;
+    }
+
+    public static Boolean verify(String jwt) throws  Exception{
+        JSONArray arr = getAuthKeys();
+        if(arr == null){
+            return false;
+        }
+        JSONObject authKey = null;
+
+        //先取苹果第一个key进行校验
+        authKey = JSONObject.parseObject(arr.getString(0));
+        if(verifyExc(jwt, authKey)){
+            return true;
+        }else{
+            //再取第二个key校验
+            authKey = JSONObject.parseObject(arr.getString(1));
+            return verifyExc(jwt, authKey);
+        }
+
+    }
+
+    /**
+     * 对前端传来的identityToken进行验证
+     * @param jwt 对应前端传来的 identityToken
+     * @param authKey 苹果的公钥 authKey
+     * @return
+     * @throws Exception
+     */
+    public static Boolean verifyExc(String jwt, JSONObject authKey) throws Exception {
+
+        Jwk jwa = Jwk.fromValues(authKey);
+        PublicKey publicKey = jwa.getPublicKey();
+
+        String aud = "";
+        String sub = "";
+        if (jwt.split("\\.").length > 1) {
+            String claim = new String(Base64.decode(jwt.split("\\.")[1]));
+            aud = JSONObject.parseObject(claim).get("aud").toString();
+            sub = JSONObject.parseObject(claim).get("sub").toString();
+        }
+        JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);
+        jwtParser.requireIssuer("https://appleid.apple.com");
+        jwtParser.requireAudience(aud);
+        jwtParser.requireSubject(sub);
+
+        try {
+            Jws<Claims> claim = jwtParser.parseClaimsJws(jwt);
+            if (claim != null && claim.getBody().containsKey("auth_time")) {
+                System.out.println(claim);
+                return true;
+            }
+            return false;
+        } catch (ExpiredJwtException e) {
+            logger.error("apple identityToken expired", e);
+            return false;
+        } catch (Exception e) {
+            logger.error("apple identityToken illegal", e);
+            return false;
+        }
+    }
+
+
+
+    /**
+     * 对前端传来的JWT字符串identityToken的第二部分进行解码
+     * 主要获取其中的aud和sub,aud大概对应ios前端的包名,sub大概对应当前用户的授权的openID
+     * @param identityToken
+     * @return  {"aud":"com.xkj.****","sub":"000***.8da764d3f9e34d2183e8da08a1057***.0***","c_hash":"UsKAuEoI-****","email_verified":"true","auth_time":1574673481,"iss":"https://appleid.apple.com","exp":1574674081,"iat":1574673481,"email":"****@qq.com"}
+     */
+    public static JSONObject parserIdentityToken(String identityToken){
+        String[] arr = identityToken.split("\\.");
+        Base64 base64 = new Base64();
+        String decode = new String (base64.decode(arr[1]));
+        String substring = decode.substring(0, decode.indexOf("}")+1);
+        JSONObject jsonObject = JSON.parseObject(substring);
+        return  jsonObject;
+    }
+
+}

+ 1 - 1
jkt-framework/src/main/java/com/miaxis/framework/config/SecurityConfig.java

@@ -102,7 +102,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 // 对于app 开放页面,允许任意访问
                 .antMatchers("/**/open-api/**").permitAll()
                 // 对于登录login 验证码captchaImage 允许匿名访问
-                .antMatchers("/login", "/login/noCode","/captchaImage","/login/code","/login/code/test","/login/jscode-test").anonymous()
+                .antMatchers("/login", "/login/noCode","/captchaImage","/login/code","/login/code/test","/login/jscode-test","/login/code/ios").anonymous()
                 //.antMatchers("/student/open/**").permitAll()
                 .antMatchers("/student/**").hasRole("STUDENT")
                 .antMatchers(

+ 11 - 0
jkt-service/src/main/java/com/miaxis/apple/service/IAppleService.java

@@ -0,0 +1,11 @@
+package com.miaxis.apple.service;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.Map;
+
+public interface IAppleService {
+
+    JSONObject getAppleUserInfo(String identityToken) throws Exception;
+
+}

+ 132 - 0
jkt-service/src/main/java/com/miaxis/apple/service/impl/AppleServiceImpl.java

@@ -0,0 +1,132 @@
+package com.miaxis.apple.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.auth0.jwk.Jwk;
+import com.miaxis.apple.service.IAppleService;
+import com.miaxis.common.exception.CustomException;
+import io.jsonwebtoken.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+import org.apache.tomcat.util.codec.binary.Base64;
+
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Map;
+
+
+@Slf4j
+@Service
+public class AppleServiceImpl  implements IAppleService {
+    @Override
+    public JSONObject getAppleUserInfo(String identityToken) throws Exception {
+
+        Map<String, Object> result = new HashMap<>(1);
+
+        //验证identityToken
+        if (!verify(identityToken)) {
+           throw new CustomException("验证identityToken失败");
+        }
+        //对identityToken解码
+        JSONObject json = parserIdentityToken(identityToken);
+        if (json == null) {
+            throw new CustomException("identityToken解码失败");
+        }
+        return json;
+    }
+
+    /**
+     * 对前端传来的JWT字符串identityToken的第二部分进行解码
+     * 主要获取其中的aud和sub,aud大概对应ios前端的包名,sub大概对应当前用户的授权的openID
+     *
+     * @param identityToken 身份token
+     * @return {"aud":"com.xkj.****","sub":"000***.8da764d3f9e34d2183e8da08a1057***.0***","c_hash":"UsKAuEoI-****","email_verified":"true","auth_time":1574673481,"iss":"https://appleid.apple.com","exp":1574674081,"iat":1574673481,"email":"****@qq.com"}
+     */
+    private JSONObject parserIdentityToken(String identityToken) {
+        String[] arr = identityToken.split("\\.");
+        String decode = new String(Base64.decodeBase64(arr[1]));
+        String substring = decode.substring(0, decode.indexOf("}") + 1);
+        return JSONObject.parseObject(substring);
+    }
+
+
+    public Boolean verify(String jwt) throws Exception {
+        JSONArray arr = getAuthKeys();
+        if (arr == null) {
+            return false;
+        }
+
+        JSONObject authKey = null;
+        //先取苹果第一个key进行校验
+        authKey = arr.getJSONObject(0);
+        if (verifyExc(jwt, authKey)) {
+            return true;
+        } else {
+            //再取第二个key校验
+            authKey = arr.getJSONObject(1);
+            return verifyExc(jwt, authKey);
+        }
+
+    }
+
+
+    /**
+     * 对前端传来的identityToken进行验证
+     *
+     * @param jwt     对应前端传来的 identityToken
+     * @param authKey 苹果的公钥 authKey
+     * @return
+     * @throws Exception
+     */
+    private static Boolean verifyExc(String jwt, JSONObject authKey) throws Exception {
+
+        Jwk jwa = Jwk.fromValues(authKey);
+        PublicKey publicKey = jwa.getPublicKey();
+
+        String aud = "";
+        String sub = "";
+        if (jwt.split("\\.").length > 1) {
+            System.out.println(jwt.split("\\.")[1]);
+            String claim = new String(Base64.decodeBase64(jwt.split("\\.")[1]));
+            aud = JSONObject.parseObject(claim).get("aud").toString();
+            sub = JSONObject.parseObject(claim).get("sub").toString();
+        }
+        JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);
+        jwtParser.requireIssuer("https://appleid.apple.com");
+        jwtParser.requireAudience(aud);
+        jwtParser.requireSubject(sub);
+
+        try {
+            Jws<Claims> claim = jwtParser.parseClaimsJws(jwt);
+            if (claim != null && claim.getBody().containsKey("auth_time")) {
+                System.out.println(claim);
+                return true;
+            }
+            return false;
+        } catch (ExpiredJwtException e) {
+            log.error("[AppleServiceImpl.verifyExc] [error] [apple identityToken expired]", e);
+            return false;
+        } catch (Exception e) {
+            log.error("[AppleServiceImpl.verifyExc] [error] [apple identityToken illegal]", e);
+            return false;
+        }
+    }
+
+
+    /**
+     * 获取苹果的公钥
+     *
+     * @return
+     */
+    private static JSONArray getAuthKeys() {
+        String url = "https://appleid.apple.com/auth/keys";
+        RestTemplate restTemplate = new RestTemplate();
+        JSONObject json = restTemplate.getForObject(url, JSONObject.class);
+        if (json != null) {
+            return json.getJSONArray("keys");
+        }
+        return null;
+    }
+}

+ 0 - 27
jkt-service/src/main/java/com/miaxis/wx/dto/CinemaData.java

@@ -1,27 +0,0 @@
-package com.miaxis.wx.dto;
-
-
-import lombok.Data;
-
-
-/**
- * 排期数据
- */
-@Data
-public class CinemaData {
-    Integer netPrice;
-    String planType;
-    String showTime;
-    String language;
-    Integer duration;
-    String showId;
-    String stopSellTime;
-    Integer cinemaId;
-    String cinemaName;
-    Integer filmId;
-    String scheduleArea;
-    String filmName;
-    String hallName;
-    String showVersionType;
-
-}

+ 0 - 28
jkt-service/src/main/java/com/miaxis/wx/dto/FilmWxOrderJsonData.java

@@ -1,28 +0,0 @@
-package com.miaxis.wx.dto;
-
-import com.miaxis.feign.dto.FilmMcpData;
-import lombok.Data;
-
-/**
- * 电影数据
- */
-@Data
-public class FilmWxOrderJsonData {
-    private static final long serialVersionUID = 1L;
-    //电影下单信息
-    private  WxOrderCreateDTO wxOrderCreateDTO;
-    //电影排场信息
-    private CinemaData cinemaData;
-    //电影订单回调信息
-    private WxOrderNotifyDTO wxOrderNotifyDTO ;
-    //快速出票
-    private FilmMcpData filmMcpData;
-
-
-
-
-
-
-
-
-}

+ 0 - 50
jkt-service/src/main/java/com/miaxis/wx/dto/FilmWxpayRefundDTO.java

@@ -1,50 +0,0 @@
-package com.miaxis.wx.dto;
-
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * 微信支付退款 dto
- */
-@Data
-public class FilmWxpayRefundDTO {
-    private static final long serialVersionUID = 1L;
-
-
-    @ApiModelProperty(value = "商户订单号")
-    private String out_trade_no;
-
-    @ApiModelProperty(value = "商户系统内部的退款单号")
-    private String out_refund_no;
-
-
-    @ApiModelProperty(value = "原因")
-    private String reason;
-
-
-    @ApiModelProperty(value = "是否允许调座,1-允许,0-不允许")
-    private WxpaySource resource;
-
-    @ApiModelProperty(value = "回调摘要")
-    private String summary;
-
-
-    @Data
-    public class WxpaySource{
-        @ApiModelProperty(value = "对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM")
-        private String algorithm;
-        @ApiModelProperty(value = "Base64编码后的开启/停用结果数据密文")
-        private String ciphertext;
-        @ApiModelProperty(value = "附加数据")
-        private String associated_data;
-        @ApiModelProperty(value = "原始回调类型,为transaction")
-        private String original_type;
-        @ApiModelProperty(value = "加密使用的随机串")
-        private String nonce;
-
-
-    }
-
-
-
-}

+ 0 - 22
jkt-service/src/main/java/com/miaxis/wx/dto/FuluWxOrderJsonData.java

@@ -1,22 +0,0 @@
-package com.miaxis.wx.dto;
-
-import com.miaxis.feign.dto.fulu.FuluGoodsInfo;
-import lombok.Data;
-
-/**
- * 电影数据
- */
-@Data
-public class FuluWxOrderJsonData {
-    private static final long serialVersionUID = 1L;
-    //视频会员下单信息
-    private  WxOrderCreateFuluDTO wxOrderCreateDTO;
-
-    //Fulu商品信息
-    private FuluGoodsInfo fuluGoodsInfo;
-
-
-    //Fulu订单详情
-    private WxFuluOrderDetailDTO wxFuluOrderDetailDTO;
-
-}

+ 0 - 70
jkt-service/src/main/java/com/miaxis/wx/dto/WxFuluOrderDetailDTO.java

@@ -1,70 +0,0 @@
-package com.miaxis.wx.dto;
-
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * 福禄订单详情
- */
-@Data
-public class WxFuluOrderDetailDTO {
-    private static final long serialVersionUID = 1L;
-
-
-
-    @ApiModelProperty(value = "福禄开放平台订单号")
-    private String order_id;
-
-    @ApiModelProperty(value = "合作商家订单号")
-    private String customer_order_no;
-
-    @ApiModelProperty(value = "充值描述")
-    private String recharge_description;
-
-    @ApiModelProperty(value = "运营商流水号")
-    private String operator_serial_number;
-
-
-    @ApiModelProperty(value = "商品Id")
-    private String product_id;
-
-    @ApiModelProperty(value = "商品名称")
-    private String product_name;
-
-    @ApiModelProperty(value = "创建时间,格式为:yyyy-MM-dd HH:mm:ss")
-    private String create_time;
-
-    @ApiModelProperty(value = "交易完成时间,格式为:yyyy-MM-dd HH:mm:ss")
-    private String charge_finish_time;
-
-
-    @ApiModelProperty(value = "充值账号")
-    private String charge_account;
-
-
-
-    @ApiModelProperty(value = "购买数量")
-    private Integer buy_num;
-
-    @ApiModelProperty(value = "订单类型:1-话费 2-流量 3-卡密 4-直充")
-    private Integer order_type;
-
-    @ApiModelProperty(value = "交易单价")
-    private Double order_price;
-
-
-    @ApiModelProperty(value = "订单状态: (success:成功,processing:处理中,failed:失败,untreated:未处理)")
-    private String order_status;
-
-    @ApiModelProperty(value = "签名")
-    private String sign;
-
-
-
-
-
-
-
-
-
-}

+ 0 - 55
jkt-service/src/main/java/com/miaxis/wx/dto/WxFuluOrderNotifyDTO.java

@@ -1,55 +0,0 @@
-package com.miaxis.wx.dto;
-
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * 微信支付回调 dto
- */
-@Data
-public class WxFuluOrderNotifyDTO {
-    private static final long serialVersionUID = 1L;
-
-
-
-    @ApiModelProperty(value = "福禄开放平台订单号")
-    private String order_id;
-
-
-    @ApiModelProperty(value = "交易完成时间,格式为:yyyy-MM-dd HH:mm:ss")
-    private String charge_finish_time;
-
-
-    @ApiModelProperty(value = "合作商家订单号")
-    private String customer_order_no;
-
-    @ApiModelProperty(value = "订单状态")
-    private String order_status;
-
-
-    @ApiModelProperty(value = "充值描述")
-    private String recharge_description;
-
-
-    @ApiModelProperty(value = "商品Id")
-    private String product_id;
-
-    @ApiModelProperty(value = "购买数量")
-    private String buy_num;
-
-    @ApiModelProperty(value = "运营商流水号")
-    private String operator_serial_number;
-
-
-    @ApiModelProperty(value = "签名")
-    private String sign;
-
-
-
-
-
-
-
-
-
-}

+ 10 - 0
jkt-service/src/main/java/com/miaxis/wx/service/impl/RefundRecordServiceImpl.java

@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.miaxis.common.config.WxpayConfig;
 import com.miaxis.common.core.domain.entity.UserInfo;
+import com.miaxis.common.enums.OrderStatusEnum;
 import com.miaxis.common.exception.CustomException;
 import com.miaxis.user.service.IUserInfoService;
 import com.miaxis.wx.domain.RefundRecord;
@@ -84,6 +85,7 @@ public class RefundRecordServiceImpl extends ServiceImpl<RefundRecordMapper, Ref
         // 返回数据:
         String bodyAsString = EntityUtils.toString(response.getEntity());
         if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
+            wxOrder.setOutRefundNo(refundCode);
             //  保存退款数据到数据库
             RefundRecord refundRecord = new RefundRecord();
             JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
@@ -95,6 +97,7 @@ public class RefundRecordServiceImpl extends ServiceImpl<RefundRecordMapper, Ref
             refundRecord.setUserReceivedAccount(jsonObject.getString("user_received_account"));
             if (jsonObject.getString("success_time")!=null){
                 refundRecord.setSuccessTime(new DateTime(jsonObject.getString("success_time")).toDate());
+                wxOrder.setTradeState("");
             }
             refundRecord.setCreateTime(new DateTime(jsonObject.getString("create_time")).toDate());
             refundRecord.setStatus(jsonObject.getString("status"));
@@ -114,6 +117,13 @@ public class RefundRecordServiceImpl extends ServiceImpl<RefundRecordMapper, Ref
             UserInfo userInfo = userInfoService.getOne(new QueryWrapper<UserInfo>().eq("openid", wxOrder.getOpenid()));
             userInfo.setIsVip(0);
             userInfoService.updateById(userInfo);
+
+
+            //改变订单状态
+
+
+
+
             WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
             wxNotifyReturnDTO.setCode("SUCCESS");
             wxNotifyReturnDTO.setMessage("成功");

+ 21 - 0
jkt-system/src/main/java/com/miaxis/system/dto/system/AppleTokenDTO.java

@@ -0,0 +1,21 @@
+package com.miaxis.system.dto.system;
+
+import com.alibaba.fastjson.JSONObject;
+import com.miaxis.common.core.domain.model.WxResult;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 【Token】DTO
+ *
+ */
+@ApiModel(value = "AppleTokenDTO", description = "AppleTokenDTO")
+@Data
+public class AppleTokenDTO {
+    private static final long serialVersionUID = 1L;
+    @ApiModelProperty(value = "令牌")
+    private String token;
+    @ApiModelProperty(value = "apple用户对象")
+    private JSONObject appleUserInfo;
+}