|  |  | 
 |  |  | import com.alibaba.fastjson.JSON; | 
 |  |  | import com.ruoyi.common.core.domain.entity.SysUser; | 
 |  |  | import com.ruoyi.common.core.domain.model.LoginUser; | 
 |  |  | import com.ruoyi.common.utils.HttpUtil; | 
 |  |  | import com.ruoyi.common.utils.StringUtils; | 
 |  |  | import com.ruoyi.common.utils.http.HttpUtils; | 
 |  |  | import com.ruoyi.framework.web.service.TokenService; | 
 |  |  | import com.ruoyi.system.service.ISysUserService; | 
 |  |  | import com.smartor.domain.SSOTokenResponse; | 
 |  |  | 
 |  |  | import javax.servlet.http.HttpServletResponse; | 
 |  |  | import java.io.IOException; | 
 |  |  | import java.net.URLEncoder; | 
 |  |  | import java.util.HashMap; | 
 |  |  | import java.util.Map; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  * SSO单点登录控制器 | 
 |  |  | 
 |  |  |      * 访问路径:http://域名:8095/sso/login | 
 |  |  |      */ | 
 |  |  |     @GetMapping("") | 
 |  |  |     public void ssoLogin(HttpServletResponse response, HttpServletRequest request) throws IOException { | 
 |  |  |     public void ssoLogin() { | 
 |  |  |         log.info("收到SSO登录请求,开始重定向到授权服务器"); | 
 |  |  |  | 
 |  |  |         // 获取客户端IP | 
 |  |  |         String clientIp = getClientIp(request); | 
 |  |  |         boolean isInternal = isInternalNetwork(clientIp); | 
 |  |  |  | 
 |  |  |         // 构建授权URL | 
 |  |  |         String authUrl = buildAuthorizationUrl(isInternal); | 
 |  |  |         log.info("重定向到授权URL: {}", authUrl); | 
 |  |  |  | 
 |  |  |         response.sendRedirect(authUrl); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * SSO回调处理 | 
 |  |  |      */ | 
 |  |  |     @GetMapping("/callback") | 
 |  |  |     public void ssoCallback(@RequestParam(required = false) String code, | 
 |  |  |                            @RequestParam(required = false) String state, | 
 |  |  |                            @RequestParam(required = false) String error, | 
 |  |  |                            HttpServletResponse response, | 
 |  |  |                            HttpServletRequest request) throws IOException { | 
 |  |  |  | 
 |  |  |         log.info("收到SSO回调,code: {}, state: {}, error: {}", code, state, error); | 
 |  |  |  | 
 |  |  |         if (error != null) { | 
 |  |  |             log.error("SSO授权失败: {}", error); | 
 |  |  |             try { | 
 |  |  |                 response.sendRedirect("/login?sso_error=" + URLEncoder.encode(error, "UTF-8")); | 
 |  |  |             } catch (Exception e) { | 
 |  |  |                 log.error("重定向失败", e); | 
 |  |  |                 response.sendRedirect("/login?sso_error=unknown_error"); | 
 |  |  |             } | 
 |  |  |             return; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         if (code == null || !this.state.equals(state)) { | 
 |  |  |             log.error("SSO回调参数错误,code: {}, state: {}", code, state); | 
 |  |  |             response.sendRedirect("/login?sso_error=invalid_callback"); | 
 |  |  |             return; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         // Authorize鉴权接口 | 
 |  |  |         String param = "client_id=" + clientId + "&redirect_uri=" + internalRedirectUri + "&response_type=code" + "&state=" + state + "&scope=" + scope; | 
 |  |  |         log.info("【Authorize鉴权接口】入参为:{}", param); | 
 |  |  |         String s = HttpUtils.sendGet(internalAuthorizeUrl, param); | 
 |  |  |         Map<String, String> result = getResult(s); | 
 |  |  |         String code = result.get("code"); | 
 |  |  |         try { | 
 |  |  |             // 获取客户端IP | 
 |  |  |             String clientIp = getClientIp(request); | 
 |  |  |             boolean isInternal = isInternalNetwork(clientIp); | 
 |  |  |             SSOTokenResponse accessToken = getAccessToken(code, true); | 
 |  |  |             SSOUserInfo userInfo = getUserInfo(accessToken.getAccess_token(), true); | 
 |  |  |  | 
 |  |  |             // 1. 用code换取access_token | 
 |  |  |             SSOTokenResponse tokenResponse = getAccessToken(code, isInternal); | 
 |  |  |             log.info("获取到access_token: {}", tokenResponse.getAccess_token()); | 
 |  |  |             createLocalSession(userInfo); | 
 |  |  |  | 
 |  |  |             // 2. 用access_token获取用户信息 | 
 |  |  |             SSOUserInfo userInfo = getUserInfo(tokenResponse.getAccess_token(), isInternal); | 
 |  |  |             log.info("获取到用户信息: {}", userInfo); | 
 |  |  |  | 
 |  |  |             // 3. 根据用户信息创建本地会话 | 
 |  |  |             String token = createLocalSession(userInfo); | 
 |  |  |  | 
 |  |  |             // 4. 重定向到前端首页,携带token | 
 |  |  |             String frontendUrl = "/#/index?token=" + token; | 
 |  |  |             response.sendRedirect(frontendUrl); | 
 |  |  |  | 
 |  |  |         } catch (RuntimeException e) { | 
 |  |  |             log.error("SSO业务处理失败: {}", e.getMessage(), e); | 
 |  |  |             try { | 
 |  |  |                 response.sendRedirect("/login?sso_error=" + URLEncoder.encode(e.getMessage(), "UTF-8")); | 
 |  |  |             } catch (Exception ex) { | 
 |  |  |                 log.error("重定向失败", ex); | 
 |  |  |                 response.sendRedirect("/login?sso_error=system_error"); | 
 |  |  |             } | 
 |  |  |         } catch (Exception e) { | 
 |  |  |             log.error("SSO登录处理失败", e); | 
 |  |  |             response.sendRedirect("/login?sso_error=login_failed"); | 
 |  |  |             e.printStackTrace(); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 构建授权URL | 
 |  |  |      */ | 
 |  |  |     private String buildAuthorizationUrl(boolean isInternal) { | 
 |  |  |         try { | 
 |  |  |             String redirectUri = getRedirectUri(isInternal); | 
 |  |  |             return getAuthorizeUrl(isInternal) + "?" + | 
 |  |  |                     "client_id=" + clientId + | 
 |  |  |                     "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8") + | 
 |  |  |                     "&response_type=code" + | 
 |  |  |                     "&state=" + state + | 
 |  |  |                     "&scope=" + URLEncoder.encode(scope, "UTF-8"); | 
 |  |  |         } catch (Exception e) { | 
 |  |  |             log.error("构建授权URL失败", e); | 
 |  |  |             throw new RuntimeException("构建授权URL失败", e); | 
 |  |  |     private Map<String, String> getResult(String param) { | 
 |  |  |         Map<String, String> paramMap = new HashMap<>(); | 
 |  |  |  | 
 |  |  |         if (param == null || !param.contains("?")) { | 
 |  |  |             return paramMap; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         String query = param.substring(param.indexOf('?') + 1); | 
 |  |  |  | 
 |  |  |         String[] pairs = query.split("&"); | 
 |  |  |  | 
 |  |  |         for (String pair : pairs) { | 
 |  |  |             String[] kv = pair.split("=", 2); | 
 |  |  |             String key = kv[0]; | 
 |  |  |             String value = kv.length > 1 ? kv[1] : ""; | 
 |  |  |             paramMap.put(key, value); | 
 |  |  |         } | 
 |  |  |         return paramMap; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  | 
 |  |  |  | 
 |  |  |         HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); | 
 |  |  |  | 
 |  |  |         ResponseEntity<String> response = restTemplate.exchange( | 
 |  |  |                 getTokenUrl(isInternal), HttpMethod.POST, request, String.class); | 
 |  |  |         ResponseEntity<String> response = restTemplate.exchange(getTokenUrl(isInternal), HttpMethod.POST, request, String.class); | 
 |  |  |  | 
 |  |  |         log.info("Token响应: {}", response.getBody()); | 
 |  |  |  | 
 |  |  | 
 |  |  |  | 
 |  |  |         HttpEntity<String> entity = new HttpEntity<>(headers); | 
 |  |  |  | 
 |  |  |         ResponseEntity<String> response = restTemplate.exchange( | 
 |  |  |                 getUserinfoUrl(isInternal), HttpMethod.GET, entity, String.class); | 
 |  |  |         ResponseEntity<String> response = restTemplate.exchange(getUserinfoUrl(isInternal), HttpMethod.GET, entity, String.class); | 
 |  |  |  | 
 |  |  |         log.info("用户信息响应: {}", response.getBody()); | 
 |  |  |  | 
 |  |  | 
 |  |  |         LoginUser loginUser = new LoginUser(localUser.getUserId(), localUser.getDeptId(), localUser, null); | 
 |  |  |  | 
 |  |  |         // 生成token | 
 |  |  |         return tokenService.createToken(loginUser); | 
 |  |  |         String token = tokenService.createToken(loginUser); | 
 |  |  |         log.info("生成的token为:{}", token); | 
 |  |  |         return token; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** |