Ver Fonte

苹果登录

小么熊🐻 há 1 ano atrás
pai
commit
a27097b039

+ 76 - 42
jsjp-admin/src/main/java/com/miaxis/system/controller/system/SysLoginController.java

@@ -17,6 +17,7 @@ import com.miaxis.feign.service.IWxService;
 import com.miaxis.framework.web.service.SysLoginService;
 import com.miaxis.framework.web.service.SysPermissionService;
 import com.miaxis.framework.web.service.TokenService;
+import com.miaxis.service.IAppleService;
 import com.miaxis.system.dto.common.RouterDTO;
 import com.miaxis.system.dto.system.TokenDTO;
 import com.miaxis.system.dto.system.UserInfoDTO;
@@ -35,6 +36,7 @@ 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 java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -46,9 +48,8 @@ import java.util.Set;
  * @author miaxis
  */
 @RestController
-@Api(tags={"【系统-登录验证】"})
-public class SysLoginController
-{
+@Api(tags = {"【系统-登录验证】"})
+public class SysLoginController {
     @Autowired
     private SysLoginService loginService;
 
@@ -67,7 +68,8 @@ public class SysLoginController
     @Autowired
     private ITmsCoachInfoService coachInfoService;
 
-
+    @Autowired
+    private IAppleService appleService;
 
 
     private static Logger logger = LoggerFactory.getLogger(SysLoginController.class);
@@ -95,14 +97,15 @@ public class SysLoginController
      */
     @PostMapping("/login")
     @ApiOperation("系统-登录方法")
-    public Response<TokenDTO> login(@RequestBody LoginBody loginBody)
-    {   TokenDTO tokenDTO = new TokenDTO();
+    public Response<TokenDTO> login(@RequestBody LoginBody loginBody) {
+        TokenDTO tokenDTO = new TokenDTO();
         // 生成令牌
         String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                 loginBody.getUuid());
         tokenDTO.setToken(token);
         return Response.success(tokenDTO);
     }
+
     /**
      * 登录方法 (不含验证码)
      *
@@ -111,8 +114,8 @@ public class SysLoginController
      */
     @PostMapping("/login/noCode")
     @ApiOperation("登录方法(不含验证码)")
-    public Response<TokenDTO> loginNoCode(@RequestBody LoginBodyNoCode loginBodyNoCode)
-    {   TokenDTO tokenDTO = new TokenDTO();
+    public Response<TokenDTO> loginNoCode(@RequestBody LoginBodyNoCode loginBodyNoCode) {
+        TokenDTO tokenDTO = new TokenDTO();
         // 生成令牌
         String token = loginService.login(loginBodyNoCode.getUsername(), loginBodyNoCode.getPassword());
         tokenDTO.setToken(token);
@@ -121,24 +124,22 @@ public class SysLoginController
 
     /**
      * 用户 jscode登录
-     *
      */
     @PostMapping("/login/jscode")
     @ApiOperation("用户jscode登录")
-    public Response<TokenDTO> getInfo(String jscode){
-        String result = wxService.getWxInfo(appid, secret, jscode,"authorization_code");
+    public Response<TokenDTO> getInfo(String jscode) {
+        String result = wxService.getWxInfo(appid, secret, jscode, "authorization_code");
         JSONObject jsonString = JSONObject.parseObject(result);
         WxResult wxResult = JSONObject.toJavaObject(jsonString, WxResult.class);
         TokenDTO tokenDTO = new TokenDTO();
         // 生成令牌
-        if (wxResult.getOpenid() != null){
+        if (wxResult.getOpenid() != null) {
             // 生成令牌
-            String token = loginService.login(wxResult.getOpenid(),null, UserLoginTypeEnum.OPENID_LOGIN.getCode());
+            String token = loginService.login(wxResult.getOpenid(), null, UserLoginTypeEnum.OPENID_LOGIN.getCode());
             tokenDTO.setToken(token);
-            return Response.success(tokenDTO) ;
-        }
-        else{
-            return Response.error(500,wxResult.getErrmsg());
+            return Response.success(tokenDTO);
+        } else {
+            return Response.error(500, wxResult.getErrmsg());
         }
 
     }
@@ -146,16 +147,15 @@ public class SysLoginController
 
     /**
      * 用户 jscode登录
-     *
      */
     @PostMapping("/login/jscode-test")
     @ApiOperation("用户jscode登录(测试,固定openid)")
-    public Response<TokenDTO> getInfoTest(String jscode){
+    public Response<TokenDTO> getInfoTest(String jscode) {
         TokenDTO tokenDTO = new TokenDTO();
-            // 生成令牌
-        String token = loginService.login("oO7PJ5CPQJo62kZWA3uiUX2KG2s4",null, UserLoginTypeEnum.OPENID_LOGIN.getCode());
+        // 生成令牌
+        String token = loginService.login("oO7PJ5CPQJo62kZWA3uiUX2KG2s4", null, UserLoginTypeEnum.OPENID_LOGIN.getCode());
         tokenDTO.setToken(token);
-        return Response.success(tokenDTO) ;
+        return Response.success(tokenDTO);
 
 
     }
@@ -163,21 +163,21 @@ public class SysLoginController
 
     @PostMapping("/login/code")
     @ApiOperation("教练管家app微信用户授权码模式登录")
-    public Response loginByWxAuthorizationCode(String authorizationCode,String city){
+    public Response loginByWxAuthorizationCode(String authorizationCode, String city) {
         String wxResultStr = wxService.getWxToken(coachAppid, coachSecret, authorizationCode, "authorization_code");
-        logger.info("微信授权码登录返回值:"+wxResultStr);
-        WxResult wxResult = JSONObject.parseObject(wxResultStr,WxResult.class);
+        logger.info("微信授权码登录返回值:" + wxResultStr);
+        WxResult wxResult = JSONObject.parseObject(wxResultStr, WxResult.class);
 
         // 生成令牌
-        if (wxResult.getErrcode() != null){
+        if (wxResult.getErrcode() != null) {
             throw new CustomException("微信授权无效,请重新授权");
         }
 
         String userInfoStr = wxService.getUserInfo("zh_CN", wxResult.getAccess_token(), wxResult.getOpenid());
-        WxUserInfo wxUserInfo = JSONObject.parseObject(userInfoStr,WxUserInfo.class);
-        ServletUtils.getRequest().setAttribute("headImage",wxUserInfo.getHeadimgurl());
-        ServletUtils.getRequest().setAttribute("nickName",wxUserInfo.getNickname());
-        ServletUtils.getRequest().setAttribute("openid",wxUserInfo.getOpenid());
+        WxUserInfo wxUserInfo = JSONObject.parseObject(userInfoStr, WxUserInfo.class);
+        ServletUtils.getRequest().setAttribute("headImage", wxUserInfo.getHeadimgurl());
+        ServletUtils.getRequest().setAttribute("nickName", wxUserInfo.getNickname());
+        ServletUtils.getRequest().setAttribute("openid", wxUserInfo.getOpenid());
 
         System.out.println(wxUserInfo.getNickname());
         System.out.println(wxUserInfo.getHeadimgurl());
@@ -189,15 +189,51 @@ public class SysLoginController
 
         TmsCoachInfoVo tmsCoachInfoVo = coachInfoService.getCoachInfoByOpenid(coachInfoOpenidDTO);
 
-        Map<String,Object> resultMap = new HashMap();
-        if(tmsCoachInfoVo==null){
-            resultMap.put("openid",wxUserInfo.getOpenid());
-            resultMap.put("coach",null);
+        Map<String, Object> resultMap = new HashMap();
+        if (tmsCoachInfoVo == null) {
+            resultMap.put("openid", wxUserInfo.getOpenid());
+            resultMap.put("coach", null);
             return Response.success(resultMap);
         } else {
-            resultMap.put("openid",null);
-            resultMap.put("coach",tmsCoachInfoVo);
-            return Response.success(resultMap) ;
+            resultMap.put("openid", null);
+            resultMap.put("coach", tmsCoachInfoVo);
+            return Response.success(resultMap);
+        }
+
+    }
+
+
+    @PostMapping("/login/code/ios")
+    @ApiOperation("教练管家Ios登录")
+    public Response iosLogin(String identityToken, String userId, String city) throws Exception {
+
+        try {
+            JSONObject appleUser = appleService.getAppleUserInfo(identityToken);
+            String sub = appleUser.getString("sub");
+
+            System.out.println("sub = " + sub);
+            System.out.println("userId = " + userId);
+
+
+            TmsCoachInfoOpenidDTO coachInfoOpenidDTO = new TmsCoachInfoOpenidDTO();
+            coachInfoOpenidDTO.setCity(city);
+            coachInfoOpenidDTO.setOpenid(sub);
+
+            TmsCoachInfoVo tmsCoachInfoVo = coachInfoService.getCoachInfoByOpenid(coachInfoOpenidDTO);
+
+            Map<String, Object> resultMap = new HashMap();
+            if (tmsCoachInfoVo == null) {
+                resultMap.put("openid", sub);
+                resultMap.put("coach", null);
+                return Response.success(resultMap);
+            } else {
+                resultMap.put("openid", null);
+                resultMap.put("coach", tmsCoachInfoVo);
+                return Response.success(resultMap);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new CustomException("获取苹果用户信息失败");
         }
 
     }
@@ -210,13 +246,12 @@ public class SysLoginController
      */
     @GetMapping("getInfo")
     @ApiOperation("获取用户信息")
-    public Response<UserInfoDTO> getInfo()
-    {
+    public Response<UserInfoDTO> getInfo() {
         SecurityUtils.getLoginUser();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         UserInfoDTO userInfoDTO = new UserInfoDTO();
         SysUser user = loginUser.getUser();
-        if (user != null){
+        if (user != null) {
             userInfoDTO.setUser(user);
             // 角色集合
             Set<String> roles = permissionService.getRolePermission(user);
@@ -236,8 +271,7 @@ public class SysLoginController
      */
     @GetMapping("getRouters")
     @ApiOperation("获取路由信息")
-    public Response<List<RouterDTO>> getRouters()
-    {
+    public Response<List<RouterDTO>> getRouters() {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         // 用户信息
         SysUser user = loginUser.getUser();

+ 6 - 0
jsjp-common/pom.xml

@@ -96,6 +96,12 @@
         <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>
 
         <!-- redis 缓存操作 -->

+ 9 - 0
jsjp-service/src/main/java/com/miaxis/service/IAppleService.java

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

+ 139 - 0
jsjp-service/src/main/java/com/miaxis/service/impl/AppleServiceImpl.java

@@ -0,0 +1,139 @@
+package com.miaxis.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.auth0.jwk.Jwk;
+import com.miaxis.common.exception.CustomException;
+import com.miaxis.service.IAppleService;
+import io.jsonwebtoken.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.util.codec.binary.Base64;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+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;
+        }
+        for (int i=0; i < arr.size() ; i ++ ){
+            JSONObject authKey = null;
+            authKey = arr.getJSONObject(i);
+            if (verifyExc(jwt, authKey)) {
+                return true;
+            }
+        }
+        return false;
+
+
+
+    }
+
+
+    /**
+     * 对前端传来的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 = "";
+        String kid = "";
+        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();
+            String firstClaim = new String(Base64.decodeBase64(jwt.split("\\.")[0]));
+            kid = JSONObject.parseObject(firstClaim).get("kid").toString();
+        }
+        if (!kid.equals(authKey.getString("kid"))){
+            return false;
+        }
+
+
+            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 - 2
jsjp-service/src/main/java/com/miaxis/tms/service/impl/TmsStudentInfoServiceImpl.java

@@ -1,8 +1,6 @@
 package com.miaxis.tms.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.miaxis.coach.domain.CoachManySchool;
-import com.miaxis.coach.service.ICoachManySchoolService;
 import com.miaxis.common.annotation.DataSource;
 import com.miaxis.common.enums.DataSourceTypeEnum;
 import com.miaxis.common.utils.bean.BeanUtils;