浏览代码

增加苹果登录模版

fangqing 4 周之前
父节点
当前提交
ac323e29de

+ 3 - 3
pom.xml

@@ -3,7 +3,7 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
-	
+
     <groupId>com.ruoyi</groupId>
     <artifactId>ruoyi</artifactId>
     <version>3.8.8</version>
@@ -11,7 +11,7 @@
     <name>ruoyi</name>
     <url>http://www.ruoyi.vip</url>
     <description>若依管理系统</description>
-    
+
     <properties>
         <ruoyi.version>3.8.8</ruoyi.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -259,4 +259,4 @@
         </pluginRepository>
     </pluginRepositories>
 
-</project>
+</project>

+ 12 - 7
ruoyi-admin/pom.xml

@@ -71,6 +71,11 @@
             <groupId>com.aliyun.oss</groupId>
             <artifactId>aliyun-sdk-oss</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>jwks-rsa</artifactId>
+            <version>0.12.0</version>
+        </dependency>
     </dependencies>
 
     <build>
@@ -90,17 +95,17 @@
                     </execution>
                 </executions>
             </plugin>
-            <plugin>   
-                <groupId>org.apache.maven.plugins</groupId>   
-                <artifactId>maven-war-plugin</artifactId>   
-                <version>3.1.0</version>   
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.1.0</version>
                 <configuration>
                     <failOnMissingWebXml>false</failOnMissingWebXml>
                     <warName>${project.artifactId}</warName>
-                </configuration>   
-           </plugin>   
+                </configuration>
+           </plugin>
         </plugins>
         <finalName>${project.artifactId}</finalName>
     </build>
 
-</project>
+</project>

+ 29 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java

@@ -14,6 +14,7 @@ import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.sign.Base64;
 import com.ruoyi.framework.web.service.SysLoginService;
 import com.ruoyi.framework.web.service.SysPermissionService;
+import com.ruoyi.generator.util.IOSToeknUtils;
 import com.ruoyi.system.service.ISysMenuService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -116,6 +117,34 @@ public class SysLoginController {
         return ajax;
     }
 
+    @RequestMapping("/appleLogin")
+    public AjaxResult appleLogin(String identityToken) {
+
+
+        // 解码后的消息体
+        JSONObject playloadObj = IOSToeknUtils.parserIdentityToken(identityToken);
+
+        System.out.println(playloadObj);
+        Boolean success;
+        try {
+            success = IOSToeknUtils.verifyExc(identityToken, playloadObj);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        if (!success) {
+            // TODO 校验token失败具体操作
+            return AjaxResult.error("登录失败");
+        }
+
+        // TODO 检验token成功具体业务操作。。。
+/*
+        String token = loginService.wxLogin(result);
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put(Constants.TOKEN, token);*/
+        return AjaxResult.success();
+    }
+
     /**
      * 登录方法
      *

+ 3 - 3
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -130,10 +130,10 @@ public class SecurityConfig {
                     permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
                     // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                     requests.antMatchers("/login","/phoneLogin", "/register", "/captchaImage","/system/user/profile/updatePwdBySmsCode").permitAll()
-                            
+
                             // 对于登录login 注册register 验证码captchaImage 微信登陆wxLogin 允许匿名访问
-                            .antMatchers("/login","/wxLogin", "/register", "/captchaImage").permitAll()
-                      
+                            .antMatchers("/login","/appleLogin","/wxLogin", "/register", "/captchaImage").permitAll()
+
                       		// 静态资源,可匿名访问
                             .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                             .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

+ 6 - 1
ruoyi-generator/pom.xml

@@ -66,7 +66,12 @@
             <artifactId>alibabacloud-dysmsapi20170525</artifactId>
             <version>3.0.0</version>
         </dependency>
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>jwks-rsa</artifactId>
+            <version>0.12.0</version>
+        </dependency>
 
     </dependencies>
 
-</project>
+</project>

+ 45 - 0
ruoyi-generator/src/main/java/com/ruoyi/TestIOSLogin.java

@@ -0,0 +1,45 @@
+package com.ruoyi;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.generator.util.IOSToeknUtils;
+
+/**
+ * @Classname TestIOSLogin
+ * @Description 测试IOS登录
+ * @Date 2023/3/23
+ * @Created by Goden
+ */
+public class TestIOSLogin {
+    public static void main(String[] args) {
+        // 请求的JWT
+        String identityToken = "eyJraWQiOiJlWGF1bm1MIiwiYWxnIjoiUlMyNTYifQ." +
+                "eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLmRpeWl5aW4ub25saW5lNTMiLCJl" +
+                "eHAiOjE1OTc2NTAxNzQsImlhdCI6MTU5NzY0OTU3NCwic3ViIjoiMDAxMzc3LmQ0ZDVmMTAwODQ0ZTQzZjdiMWM1O" +
+                "WRiMzUyZWZkZmI4LjAyNTkiLCJjX2hhc2giOiJkTDVRdld2VTNjVHBxczNSazlUTnRBIiwiZW1haWwiOiI0OTk4O" +
+                "TY1MDdAcXEuY29tIiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwiYXV0aF90aW1lIjoxNTk3NjQ5NTc0LCJub25jZV9" +
+                "zdXBwb3J0ZWQiOnRydWV9." +
+                "hM9HjNsMJW2PjYP7SfbzF-GqOt0VnMjYGq4BoU68rkQ-K2lPp_ae5ziX6Bbr3WHg" +
+                "6cc3Z8OzGO63OfExvSj9gQTR596CZLvNGXhbI3piTK6597-cYsPCTbY7xHxgdHLuL8XhD-9dXPn9rouVYu4QA1" +
+                "8JBQG1Q4sGsRzLEJ5DjOM9x1bkBz4Vu_5LEOefHFHkWN_RPCh_AOJGviDzm81kTkCTWn8jpm0tGdevMR93MOf44" +
+                "f7bjP2T8yezl0Vbv09TrnkdAqG0BsihCD0VN9JV7X2eagyumoxTdFfoRiOflFKAaQqohVzcqy9tHOGm_6w5h8bsR" +
+                "CmtBC4PnqIFqNy_AQ";
+        // 解码后的消息体
+        JSONObject playloadObj = IOSToeknUtils.parserIdentityToken(identityToken);
+
+        System.out.println(playloadObj);
+        Boolean success;
+        try {
+            success = IOSToeknUtils.verifyExc(identityToken, playloadObj);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        if (!success) {
+            // TODO 校验token失败具体操作
+            return;
+        }
+
+        // TODO 检验token成功具体业务操作。。。
+    }
+}

+ 98 - 0
ruoyi-generator/src/main/java/com/ruoyi/generator/util/IOSToeknUtils.java

@@ -0,0 +1,98 @@
+package com.ruoyi.generator.util;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.auth0.jwk.Jwk;
+import io.jsonwebtoken.*;
+import org.springframework.web.client.RestTemplate;
+
+import java.nio.charset.StandardCharsets;
+import java.security.PublicKey;
+import java.util.Base64;
+import java.util.Map;
+
+/**
+ * @Classname IOSToeknUtils
+ * @Description IOS token操作工具
+ * @Date 2023/03/23
+ * @Created by Goden
+ */
+public class IOSToeknUtils {
+
+    private final static String authUrl = "https://appleid.apple.com/auth/keys";
+
+    private final static String authIss = "https://appleid.apple.com";
+
+    /**
+     * 解码identityToken
+     * @param identityToken
+     * @return
+     */
+    public static JSONObject parserIdentityToken(String identityToken) {
+        String[] arr = identityToken.split("\\.");
+
+        String firstDate = new String(Base64.getDecoder().decode(arr[0]), StandardCharsets.UTF_8);
+        String decode = new String(Base64.getDecoder().decode(arr[1]), StandardCharsets.UTF_8);
+        JSONObject claimObj = JSON.parseObject(decode);
+        // 将第一部分获取到的kid放入消息体中,方便后续匹配对应的公钥使用
+        claimObj.put("kid", JSONObject.parseObject(firstDate).get("kid"));
+        return claimObj;
+    }
+
+    /**
+     * 根据kid获取对应的苹果公钥
+     * @param kid
+     * @return
+     */
+    public static PublicKey getPublicKey(String kid) {
+        try {
+            RestTemplate restTemplate = new RestTemplate();
+            JSONObject data = restTemplate.getForObject(authUrl, JSONObject.class);
+            assert data != null;
+            JSONArray jsonArray = data.getJSONArray("keys");
+            for (Object obj : jsonArray) {
+                Map json = ((Map) obj);
+                // 获取kid对应的公钥
+                if (json.get("kid").equals(kid)) {
+                    Jwk jwa = Jwk.fromValues(json);
+                    return jwa.getPublicKey();
+                }
+            }
+        } catch (Exception e) {
+
+        }
+        return null;
+    }
+
+    /**
+     * 对前端传来的identityToken进行验证
+     *
+     * @param identityToken
+     * @param jsonObject
+     * @return
+     * @throws Exception
+     */
+    public static Boolean verifyExc(String identityToken, JSONObject jsonObject) throws Exception {
+        String kid = (String) jsonObject.get("kid");
+        PublicKey publicKey = getPublicKey(kid);
+
+        JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);
+        jwtParser.requireIssuer(authIss);
+        jwtParser.requireAudience((String) jsonObject.get("aud"));
+        jwtParser.requireSubject((String) jsonObject.get("sub"));
+        try {
+            Jws<Claims> claim = jwtParser.parseClaimsJws(identityToken);
+            if (claim != null && claim.getBody().containsKey("auth_time")) {
+                return true;
+            }
+            return false;
+        } catch (ExpiredJwtException e) {
+            return false;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}
+