xiatian 2 viikkoa sitten
commit
895a6430a6

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

BIN
lib/cas-client-core-3.2.1.jar


+ 91 - 0
pom.xml

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>cn.com.qmth.ac</groupId>
+	<artifactId>auth-center</artifactId>
+	<version>1.0.0</version>
+	<packaging>jar</packaging>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.3.12.RELEASE</version>
+		<relativePath />
+	</parent>
+    <properties>
+        <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
+        <mybatis-plus.version>3.4.3.3</mybatis-plus.version>
+        <maven-compiler-version>3.8.1</maven-compiler-version>
+        <maven-surefire-version>2.22.2</maven-surefire-version>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <qmth-boot-version>1.0.6</qmth-boot-version>
+    </properties>
+
+    <dependencies>
+      <dependency>
+        <groupId>com.qmth.boot</groupId>
+        <artifactId>starter-api</artifactId>
+        <version>${qmth-boot-version}</version>
+      </dependency>
+            <dependency>
+        <groupId>org.jsoup</groupId>
+        <artifactId>jsoup</artifactId>
+        <version>1.14.2</version>
+      </dependency>
+      		<!-- Swagger Jars start -->
+		<dependency>
+			<groupId>com.github.xiaoymin</groupId>
+			<artifactId>knife4j-spring-boot-starter</artifactId>
+			<version>2.0.9</version>
+		</dependency>
+		<dependency>
+			<groupId>io.swagger</groupId>
+			<artifactId>swagger-annotations</artifactId>
+			<version>1.5.24</version>
+		</dependency>
+		<dependency>
+			<groupId>io.swagger</groupId>
+			<artifactId>swagger-models</artifactId>
+			<version>1.5.24</version>
+		</dependency>
+		<!-- Swagger Jars end -->
+      <dependency>
+        <groupId>org.apache.commons</groupId>
+        <artifactId>commons-lang3</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>com.alibaba</groupId>
+        <artifactId>fastjson</artifactId>
+        <version>1.2.68</version>
+      </dependency>
+      <dependency>
+        <groupId>commons-io</groupId>
+        <artifactId>commons-io</artifactId>
+        <version>2.6</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.httpcomponents</groupId>
+        <artifactId>httpclient</artifactId>
+      </dependency>
+    
+    </dependencies>
+
+    <build>
+		<finalName>${project.artifactId}</finalName>
+
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<configuration>
+					<includeSystemScope>true</includeSystemScope>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+
+</project>

+ 14 - 0
src/main/java/cn/com/qmth/ac/Application.java

@@ -0,0 +1,14 @@
+package cn.com.qmth.ac;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+
+@SpringBootApplication(scanBasePackages = "com.qmth.*", exclude = { SecurityAutoConfiguration.class })
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+
+}

+ 80 - 0
src/main/java/cn/com/qmth/ac/bean/RedirectParam.java

@@ -0,0 +1,80 @@
+package cn.com.qmth.ac.bean;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class RedirectParam {
+
+    private String loginName;
+
+    @ApiModelProperty("学校编码")
+    private String schoolCode;
+
+    @ApiModelProperty("返回url")
+    private String returnUrl;
+
+    private String appId;
+
+    private String rootOrgId;
+
+    private String secretKey;
+
+    // tk是否有效
+    private Boolean ticketValid;
+
+    public String getLoginName() {
+        return loginName;
+    }
+
+    public void setLoginName(String loginName) {
+        this.loginName = loginName;
+    }
+
+    public String getSchoolCode() {
+        return schoolCode;
+    }
+
+    public void setSchoolCode(String schoolCode) {
+        this.schoolCode = schoolCode;
+    }
+
+    public String getReturnUrl() {
+        return returnUrl;
+    }
+
+    public void setReturnUrl(String returnUrl) {
+        this.returnUrl = returnUrl;
+    }
+
+    public Boolean getTicketValid() {
+        return ticketValid;
+    }
+
+    public void setTicketValid(Boolean ticketValid) {
+        this.ticketValid = ticketValid;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getRootOrgId() {
+        return rootOrgId;
+    }
+
+    public void setRootOrgId(String rootOrgId) {
+        this.rootOrgId = rootOrgId;
+    }
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+}

+ 70 - 0
src/main/java/cn/com/qmth/ac/bean/SpringContextHolder.java

@@ -0,0 +1,70 @@
+package cn.com.qmth.ac.bean;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.ResolvableType;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringContextHolder implements ApplicationContextAware {
+
+    private static ApplicationContext ctx = null;
+
+    @Override
+    public void setApplicationContext(ApplicationContext ctx) {
+        SpringContextHolder.ctx = ctx;
+    }
+
+    public static ApplicationContext getApplicationContext() {
+        return ctx;
+    }
+
+    public static Object getBean(String name) {
+        return ctx.getBean(name);
+    }
+
+    public static <T> T getBean(String name, Class<T> requiredType) {
+        return ctx.getBean(name, requiredType);
+    }
+
+    public static <T> T getBean(Class<T> requiredType) {
+        return ctx.getBean(requiredType);
+    }
+
+    public static Object getBean(String name, Object... args) {
+        return ctx.getBean(name, args);
+    }
+
+    public static <T> T getBean(Class<T> requiredType, Object... args) {
+        return ctx.getBean(requiredType, args);
+    }
+
+    public static boolean containsBean(String name) {
+        return ctx.containsBean(name);
+    }
+
+    public static boolean isSingleton(String name) {
+        return ctx.isSingleton(name);
+    }
+
+    public static boolean isPrototype(String name) {
+        return ctx.isPrototype(name);
+    }
+
+    public static boolean isTypeMatch(String name, ResolvableType typeToMatch) {
+        return ctx.isTypeMatch(name, typeToMatch);
+    }
+
+    public static boolean isTypeMatch(String name, Class<?> typeToMatch) {
+        return ctx.isTypeMatch(name, typeToMatch);
+    }
+
+    public static Class<?> getType(String name) {
+        return ctx.getType(name);
+    }
+
+    public static String[] getAliases(String name) {
+        return ctx.getAliases(name);
+    }
+
+}

+ 170 - 0
src/main/java/cn/com/qmth/ac/bean/SystemConstant.java

@@ -0,0 +1,170 @@
+package cn.com.qmth.ac.bean;
+
+import javax.servlet.http.HttpServletRequest;
+
+import cn.com.qmth.ac.util.ServletUtil;
+
+public class SystemConstant {
+
+    /**
+     * 广药mq请求参数
+     */
+    public static final String DEFAULT_DATE = "yyyyMMdd";
+
+    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
+
+    public static final String GDPU_SYS_APP_ID = "sysAppId";
+
+    public static final String GDPU_APP_ID_PARAM = "gdpuAppId";
+
+    public static final String GDPU_APP_SECRET_PARAM = "gdpuAppSecret";
+
+    public static final String GDPU_SYS_APP_ID_PARAM = "gdpuSysAppId";
+
+    public static final String GDPU_SERVICE_ADDRESS_PARAM = "gdpuServiceAddress";
+
+    public static final String GDPU_DOCUN_ID = "docunId";
+
+    public static final String GDPU_HEADER_APP_ID = "appid";
+
+    public static final String GDPU_HEADER_APP_SECRET = "secret";
+
+    public static final String GDPU_CAS_MQ_URL = "http://examsso.gdpu.edu.cn/api/open/gdpu/mq/account";
+
+    /**
+     * api前缀
+     */
+    public static final String PREFIX_URL_OPEN = "/open";
+
+    public static final String PREFIX_URL_GDPU_GET_BACK_LOG = "/getbacklog";
+
+    public static final String PREFIX_URL_GDPU_MQ = "/open/mq";
+
+    public static final String PREFIX_URL_ADMIN = "/admin";
+
+    /**
+     * 系统常量
+     */
+    public static final String CLIENT_SYSTEM_EXPLICIT_PORT = "";
+
+    public static final String SERVICE_KEY = "service";
+
+    public static final String CAS_ADDRESS = "casAddress";
+
+    public static final String SCHOOL_SERVICE_ADDRESS = "schoolServiceAddress";
+
+    public static final String CHARSET_NAME = "UTF-8";
+
+    public static final String SUCCESS = "success";
+
+    public static final String UPDATE_TIME = "updateTime";
+
+    public static final String SESSION = "session:";
+
+    public static final String USER = "account";
+
+    public static final String FUNCTIONAL_TYPE = "functionalType";
+
+    public static final String SCHOOL_ID = "schoolId";
+
+    public static final String SCHOOL = "school";
+
+    public static final String RETURN_URL = "returnUrl";
+
+    public static final String PARAMS = "params";
+
+    public static final String ORG = "org";
+
+    public static final String MD5 = "MD5";
+
+    public static final String ID = "id";
+
+    public static final String SIGNATURE = "signature";
+
+    public static final String GET = "get";
+
+    public static final String GET_UNKNOWN = "?";
+
+    public static final String GET_SYMBOL = "&";
+
+    public static final String GET_EQUAL = "=";
+
+    public static final String PATH_MATCH = "*";
+
+    public static final String PATH_SUBSTR = "/";
+
+    public static final String METHOD = "post";
+
+    public static final String TEACH_CLOUD_PRINT = "teachcloudPrint";
+
+    public static final String CAS_VUE_LOGIN_PATH = "/login-open";
+
+    public static final String SCHOOL_CODE = "${schoolCode}";
+
+    public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
+
+    /**
+     * 缓存配置
+     */
+    public static final String SCHOOL_CACHE = "school:cache";
+
+    public static final String SCHOOL_CODE_CACHE = "school:code:cache";
+
+    public static final String SYS_SETTING_CACHE = "sys:setting:cache";
+
+    /**
+     * 鉴权
+     */
+    public static final String HEADER_AUTHORIZATION = "Authorization";
+
+    public static final String HEADER_TIME = "time";
+
+    public static final String HEADER_PLATFORM = "platform";
+
+    public static final String HEADER_DEVICE_ID = "deviceId";
+
+    public static final String TOKEN = "token";
+
+    public static final String SIGN = "sign";
+
+    public static final String LOG_ERROR = "请求出错:{}";
+
+    /**
+     * http设置
+     */
+    public static final int CONNECT_TIME_OUT = 1000 * 60 * 2;// 请求超时
+
+    public static final int SOCKET_CONNECT_TIME_OUT = 1000 * 60 * 30;// 读取数据超时
+
+    /**
+     * 获得基础路径
+     *
+     * @return
+     */
+    public static String getBasePath() {
+        HttpServletRequest request = ServletUtil.getRequest();
+        String scheme = request.getScheme();
+        String serverName = request.getServerName();
+        int serverPort = request.getServerPort();
+        String contextPath = request.getContextPath();
+
+        // 判断是否配置了显式端口
+        boolean explicit_port = CLIENT_SYSTEM_EXPLICIT_PORT != null && !"".equals(CLIENT_SYSTEM_EXPLICIT_PORT);
+        if (explicit_port) {
+            try {
+                serverPort = Integer.parseInt(CLIENT_SYSTEM_EXPLICIT_PORT);
+            } catch (Exception e) {
+                // 异常时赋值,方便双方排查问题
+                serverPort = 19000;
+            }
+            return scheme + "://" + serverName + ":" + serverPort + contextPath + "/";
+        } else {
+            if ((serverPort == 80) || (serverPort == 443)) {
+                return scheme + "://" + serverName + contextPath;
+            } else {
+                return scheme + "://" + serverName + ":" + serverPort + contextPath;
+            }
+        }
+    }
+
+}

+ 34 - 0
src/main/java/cn/com/qmth/ac/config/Swagger2.java

@@ -0,0 +1,34 @@
+package cn.com.qmth.ac.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
+
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+@EnableKnife4j
+@Configuration
+@EnableSwagger2WebMvc
+public class Swagger2 {
+
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
+                .apis(RequestHandlerSelectors.basePackage("cn.com.qmth.ac.controller")).paths(PathSelectors.any())
+                .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder().title("API doc").contact(new Contact("qmth", "http://xxxxx/", "")).version("xxx")
+                .description("API文档").build();
+    }
+
+}

+ 50 - 0
src/main/java/cn/com/qmth/ac/controller/OpenApiController.java

@@ -0,0 +1,50 @@
+package cn.com.qmth.ac.controller;
+
+import javax.annotation.Resource;
+
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.constant.ApiConstant;
+
+import cn.com.qmth.ac.bean.RedirectParam;
+import cn.com.qmth.ac.bean.SystemConstant;
+import cn.com.qmth.ac.service.CommonService;
+import cn.com.qmth.ac.util.Result;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_OPEN)
+@Validated
+public class OpenApiController {
+
+    @Resource
+    private CommonService commonService;
+
+    @ApiOperation(value = "cas鉴权接口")
+    @ApiResponses({ @ApiResponse(code = 200, message = "返回消息", response = Result.class) })
+    @RequestMapping(value = "auth/login/{schoolCode}", method = RequestMethod.GET)
+    @Aac(auth = false)
+    public void authentication(@ApiParam(value = "学校编码") @PathVariable("schoolCode") String schoolCode) {
+        RedirectParam redirectParams = commonService.authentication(schoolCode);
+        commonService.redirect(redirectParams);
+    }
+
+    @ApiOperation(value = "cas鉴权退出接口")
+    @RequestMapping(value = "auth/logout/{schoolCode}", method = RequestMethod.GET)
+    @ApiResponses({ @ApiResponse(code = 200, message = "返回消息", response = Result.class) })
+    @Aac(auth = false)
+    public void logout(@ApiParam(value = "学校编码") @PathVariable("schoolCode") String schoolCode,
+            @ApiParam(value = "sessionId", required = false) @RequestParam(required = false) String gSessionId) {
+        commonService.logout(schoolCode);
+    }
+
+}

+ 12 - 0
src/main/java/cn/com/qmth/ac/service/CommonService.java

@@ -0,0 +1,12 @@
+package cn.com.qmth.ac.service;
+
+import cn.com.qmth.ac.bean.RedirectParam;
+
+public interface CommonService {
+
+    RedirectParam authentication(String schoolCode);
+
+    void logout(String schoolCode);
+
+    public void redirect(RedirectParam param);
+}

+ 184 - 0
src/main/java/cn/com/qmth/ac/service/impl/CommonServiceImpl.java

@@ -0,0 +1,184 @@
+package cn.com.qmth.ac.service.impl;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.select.Elements;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+
+import com.qmth.boot.core.exception.StatusException;
+
+import cn.com.qmth.ac.bean.RedirectParam;
+import cn.com.qmth.ac.bean.SystemConstant;
+import cn.com.qmth.ac.service.CommonService;
+import cn.com.qmth.ac.util.ByteUtil;
+import cn.com.qmth.ac.util.HttpUtil;
+import cn.com.qmth.ac.util.SHA256;
+import cn.com.qmth.ac.util.ServletUtil;
+
+@Service
+public class CommonServiceImpl implements CommonService {
+
+    private final static Logger log = LoggerFactory.getLogger(CommonServiceImpl.class);
+
+    @Autowired
+    private Environment environment;
+
+    @Override
+    public void redirect(RedirectParam param) {
+
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setHeader(SystemConstant.ACCESS_CONTROL_ALLOW_ORIGIN, SystemConstant.PATH_MATCH);
+
+        try {
+            if (param.getTicketValid()) {
+                long timestamp = System.currentTimeMillis();
+                String secretKey = param.getSecretKey();
+                StringBuilder joinStr = new StringBuilder().append(param.getRootOrgId()).append(param.getAppId())
+                        .append(timestamp).append(secretKey);
+                byte[] bytes = SHA256.encode(joinStr.toString());
+                String token = ByteUtil.toHexAscii(bytes);
+                String url = param.getReturnUrl() + "/#/access?loginName=" + param.getLoginName() + "&orgId="
+                        + param.getRootOrgId() + "&appId=" + param.getAppId() + "&timestamp=" + timestamp + "&token="
+                        + token + "&from=cas";
+                response.sendRedirect(url);
+            } else {
+                response.sendRedirect(param.getReturnUrl());
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public RedirectParam authentication(String schoolCode) {
+        HttpServletRequest request = ServletUtil.getRequest();
+        String authserver = environment.getProperty("cas.authserver." + schoolCode.toLowerCase());
+        if (StringUtils.isBlank(authserver)) {
+            throw new StatusException(schoolCode + "未配置cas.authserver");
+        }
+        String authlogin = environment.getProperty("cas.authlogin." + schoolCode.toLowerCase());
+        if (StringUtils.isBlank(authserver)) {
+            throw new StatusException(schoolCode + "未配置cas.authlogin");
+        }
+
+        String authlogout = environment.getProperty("cas.authlogout." + schoolCode.toLowerCase());
+        if (StringUtils.isBlank(authlogout)) {
+            throw new StatusException(schoolCode + "未配置cas.authlogout");
+        }
+
+        String ecLogin = environment.getProperty("examcloud.login." + schoolCode.toLowerCase());
+        if (StringUtils.isBlank(ecLogin)) {
+            throw new StatusException(schoolCode + "未配置examcloud.login");
+        }
+
+        String appId = environment.getProperty("examcloud.app-id." + schoolCode.toLowerCase());
+        if (StringUtils.isBlank(appId)) {
+            throw new StatusException(schoolCode + "未配置examcloud.app-id");
+        }
+
+        String rootOrgId = environment.getProperty("examcloud.root-org-id." + schoolCode.toLowerCase());
+        if (StringUtils.isBlank(rootOrgId)) {
+            throw new StatusException(schoolCode + "未配置examcloud.root-org-id");
+        }
+        String secretKey = environment.getProperty("examcloud.secret-key." + schoolCode.toLowerCase());
+        if (StringUtils.isBlank(secretKey)) {
+            throw new StatusException(schoolCode + "未配置examcloud.login");
+        }
+
+        RedirectParam rp = new RedirectParam();
+
+        rp.setAppId(appId);
+        rp.setRootOrgId(rootOrgId);
+        rp.setSecretKey(secretKey);
+
+        String tkt = request.getParameter("ticket");
+        if (Objects.isNull(tkt) || tkt.length() == 0) {
+            rp.setTicketValid(false);
+            rp.setReturnUrl(authlogin);
+        } else {// 校验ticket,获取用户信息
+            // 发送请求
+            Map<String, Object> map = new LinkedHashMap<>();
+            map.put("ticket", tkt);
+            map.put(SystemConstant.SERVICE_KEY, ecLogin);
+            try {
+                String data = HttpUtil.get(authserver, map, null, System.currentTimeMillis());
+                log.warn("data:{}", data);
+                if (data == null) {
+                    rp.setTicketValid(false);
+                    rp.setReturnUrl(authlogin);
+                } else {
+                    String loginName = getLoginName(data);
+                    if (StringUtils.isBlank(loginName)) {
+                        rp.setTicketValid(false);
+                        rp.setReturnUrl(authlogin);
+                    } else {
+                        rp.setTicketValid(true);
+                        rp.setLoginName(loginName);
+                        rp.setReturnUrl(ecLogin);
+                    }
+                }
+            } catch (IOException e) {
+                throw new StatusException("ticket校验出错", e);
+            }
+        }
+        return rp;
+    }
+
+    private String getLoginName(String data) {
+        Document doc = Jsoup.parse(data);
+        Elements user = doc.getElementsByTag("cas:user");
+        if (user == null || user.size() != 1) {
+            return null;
+        }
+        return user.get(0).text().trim();
+    }
+
+    @Override
+    public void logout(String schoolCode) {
+        HttpServletResponse response = ServletUtil.getResponse();
+
+        response.setHeader(SystemConstant.ACCESS_CONTROL_ALLOW_ORIGIN, SystemConstant.PATH_MATCH);
+        try {
+            response.sendRedirect(getLogoutUrl(schoolCode));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private String getLogoutUrl(String schoolCode) {
+        String authlogout = environment.getProperty("cas.authlogout." + schoolCode.toLowerCase());
+        if (StringUtils.isBlank(authlogout)) {
+            throw new StatusException(schoolCode + "未配置cas.authlogout");
+        }
+
+        String host = environment.getProperty("ac.host");
+        if (StringUtils.isBlank(host)) {
+            throw new StatusException("未配置ac.host");
+        }
+
+        try {
+            String loginUrlRoot = host + "/api/open/auth/login/" + schoolCode;
+            String encodeLoginUrlRoot = URLEncoder.encode(loginUrlRoot, StandardCharsets.UTF_8.toString());
+            return authlogout + SystemConstant.GET_UNKNOWN + SystemConstant.SERVICE_KEY + SystemConstant.GET_EQUAL
+                    + encodeLoginUrlRoot;
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 38 - 0
src/main/java/cn/com/qmth/ac/util/ByteUtil.java

@@ -0,0 +1,38 @@
+package cn.com.qmth.ac.util;
+
+import java.io.StringWriter;
+
+/**
+ * 字节转换工具
+ */
+public class ByteUtil {
+
+    public static String toHexAscii(byte[] bytes) {
+        int len = bytes.length;
+
+        StringWriter sw = new StringWriter(len * 2);
+        for (int i = 0; i < len; ++i) {
+            addHexAscii(bytes[i], sw);
+        }
+        return sw.toString();
+    }
+
+    public static void addHexAscii(byte b, StringWriter sw) {
+        int ub = b & 0xff;
+        int h1 = ub / 16;
+        int h2 = ub % 16;
+        sw.write(toHexDigit(h1));
+        sw.write(toHexDigit(h2));
+    }
+
+    public static char toHexDigit(int h) {
+        char out;
+        if (h <= 9) {
+            out = (char) (h + 0x30);
+        } else {
+            out = (char) (h + 0x37);
+        }
+        return out;
+    }
+
+}

+ 256 - 0
src/main/java/cn/com/qmth/ac/util/HttpUtil.java

@@ -0,0 +1,256 @@
+package cn.com.qmth.ac.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.EntityUtils;
+import org.apache.tomcat.util.http.fileupload.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.ac.bean.SystemConstant;
+
+public class HttpUtil {
+
+    private final static Logger log = LoggerFactory.getLogger(HttpUtil.class);
+
+    /**
+     * post json
+     *
+     * @param url
+     * @param json
+     * @param secret
+     * @param timestamp
+     * @return
+     * @throws IOException
+     */
+    public static String postJson(String url, String json, String secret, Long timestamp) throws IOException {
+        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(SystemConstant.CONNECT_TIME_OUT)// 连接主机服务超时时间
+                .setConnectionRequestTimeout(SystemConstant.CONNECT_TIME_OUT)// 请求超时时间
+                .setSocketTimeout(SystemConstant.SOCKET_CONNECT_TIME_OUT)// 数据读取超时时间
+                .build();
+
+        // 构建post请求
+        HttpPost post = new HttpPost(url);
+        post.setConfig(requestConfig);
+        post.setHeader(SystemConstant.HEADER_AUTHORIZATION, secret);
+        post.setHeader(SystemConstant.HEADER_TIME, String.valueOf(timestamp));
+        post.setHeader(HTTP.CONTENT_TYPE, "application/json; charset=" + SystemConstant.CHARSET_NAME);
+        post.setHeader("Accept", "application/json");
+
+        String encoderJson = URLEncoder.encode(json, SystemConstant.CHARSET_NAME);
+        StringEntity se = new StringEntity(encoderJson);
+        se.setContentType("text/json");
+        se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
+        post.setEntity(se);
+        // 执行请求,获取响应
+        return getRespString(post);
+    }
+
+    /**
+     * post 请求
+     *
+     * @param url
+     * @param params
+     * @param secret
+     * @param timestamp
+     * @return
+     */
+    public static String post(String url, Map<String, Object> params, String secret, Long timestamp)
+            throws IOException {
+        // 构建post请求
+        HttpPost post = new HttpPost(url);
+        post.setHeader(SystemConstant.HEADER_AUTHORIZATION, secret);
+        post.setHeader(SystemConstant.HEADER_TIME, String.valueOf(timestamp));
+        post.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=" + SystemConstant.CHARSET_NAME);
+        // 构建请求参数
+        List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
+        if (params != null) {
+            for (String key : params.keySet()) {
+                pairs.add(new BasicNameValuePair(key, String.valueOf(params.get(key))));
+            }
+        }
+        HttpEntity entity = null;
+        try {
+            entity = new UrlEncodedFormEntity(pairs, SystemConstant.CHARSET_NAME);
+        } catch (UnsupportedEncodingException e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        }
+        post.setEntity(entity);
+        // 执行请求,获取响应
+        return getRespString(post);
+    }
+
+    /**
+     * post 请求
+     *
+     * @param url
+     * @param params
+     * @param accessToken
+     * @return
+     */
+    public static String post(String url, Map<String, Object> params, String accessToken) throws IOException {
+        // 构建post请求
+        HttpPost post = new HttpPost(url);
+        post.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=" + SystemConstant.CHARSET_NAME);
+        post.setHeader("X-Access-Token", accessToken);
+        // 构建请求参数
+        List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
+        if (params != null) {
+            for (String key : params.keySet()) {
+                pairs.add(new BasicNameValuePair(key, String.valueOf(params.get(key))));
+            }
+        }
+        HttpEntity entity = null;
+        try {
+            entity = new UrlEncodedFormEntity(pairs, SystemConstant.CHARSET_NAME);
+        } catch (UnsupportedEncodingException e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        }
+        post.setEntity(entity);
+        // 执行请求,获取响应
+        return getRespString(post);
+    }
+
+    /**
+     * get 请求
+     *
+     * @param url
+     * @param params
+     * @param secret
+     * @param timestamp
+     * @return
+     */
+    public static String get(String url, Map<String, Object> params, String secret, Long timestamp) throws IOException {
+        // 构建请求参数
+        List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
+        if (params != null) {
+            for (String key : params.keySet()) {
+                pairs.add(new BasicNameValuePair(key, String.valueOf(params.get(key))));
+            }
+        }
+        String str = EntityUtils.toString(new UrlEncodedFormEntity(pairs, StandardCharsets.UTF_8));// 转换为键值对
+        HttpGet get = new HttpGet(url + SystemConstant.GET_UNKNOWN + str);
+        if (Objects.nonNull(secret)) {
+            get.setHeader(SystemConstant.HEADER_AUTHORIZATION, secret);
+        }
+        if (Objects.nonNull(timestamp)) {
+            get.setHeader(SystemConstant.HEADER_TIME, String.valueOf(timestamp));
+        }
+        // 执行请求,获取响应
+        return getRespString(get);
+    }
+
+    /**
+     * 获取响应信息
+     *
+     * @param request
+     * @return
+     */
+    public static String getRespString(HttpUriRequest request) throws IOException {
+        // 获取响应流
+        InputStream in = null;
+        ByteArrayOutputStream ou = null;
+        try {
+            in = getRespInputStream(request);
+            ou = new ByteArrayOutputStream();
+            IOUtils.copy(in, ou);
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        } finally {
+            if (Objects.nonNull(in)) {
+                in.close();
+            }
+            if (Objects.nonNull(ou)) {
+                ou.close();
+            }
+        }
+        return Objects.nonNull(ou) ? new String(ou.toByteArray(), StandardCharsets.UTF_8) : null;
+    }
+
+    /**
+     * 获取输入流
+     *
+     * @param request
+     * @return
+     */
+    public static InputStream getRespInputStream(HttpUriRequest request) {
+        // 获取响应对象
+        HttpResponse response = null;
+        try {
+            response = HttpClients.createDefault().execute(request);
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        }
+        if (response == null) {
+            return null;
+        }
+        // 获取Entity对象
+        HttpEntity entity = response.getEntity();
+        // 获取响应信息流
+        InputStream in = null;
+        if (entity != null) {
+            try {
+                in = entity.getContent();
+            } catch (Exception e) {
+                log.error(SystemConstant.LOG_ERROR, e);
+            }
+        }
+        return in;
+    }
+
+    /**
+     * post 广药请求
+     *
+     * @param url
+     * @param params
+     * @param appid
+     * @param secret
+     * @param timestamp
+     * @return
+     */
+    public static String postGdpu(String url, Map<String, Object> params, String appid, String secret, Long timestamp)
+            throws IOException {
+        // 构建post请求
+        HttpPost post = new HttpPost(url);
+        post.setHeader(SystemConstant.GDPU_HEADER_APP_ID, appid);
+        post.setHeader(SystemConstant.GDPU_HEADER_APP_SECRET, secret);
+        post.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=" + SystemConstant.CHARSET_NAME);
+        // 构建请求参数
+        List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
+        if (params != null) {
+            for (String key : params.keySet()) {
+                pairs.add(new BasicNameValuePair(key, String.valueOf(params.get(key))));
+            }
+        }
+        HttpEntity entity = null;
+        try {
+            entity = new UrlEncodedFormEntity(pairs, SystemConstant.CHARSET_NAME);
+        } catch (UnsupportedEncodingException e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        }
+        post.setEntity(entity);
+        // 执行请求,获取响应
+        return getRespString(post);
+    }
+}

+ 63 - 0
src/main/java/cn/com/qmth/ac/util/Result.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.ac.util;
+
+public class Result {
+
+    private int code;
+
+    private String message;
+
+    private Object data;
+
+    public Result() {
+
+    }
+
+    public Result(int code) {
+        this.code = code;
+    }
+
+    public Result(String message) {
+        this.message = message;
+    }
+
+    public Result(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Result(int code, String message, Object data) {
+        this.code = code;
+        this.message = message;
+        this.data = data;
+    }
+
+    public Result(int code, Object data, String message) {
+        this.code = code;
+        this.data = data;
+        this.message = message;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+}

+ 23 - 0
src/main/java/cn/com/qmth/ac/util/SHA256.java

@@ -0,0 +1,23 @@
+package cn.com.qmth.ac.util;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * SHA256加密
+ */
+public class SHA256 {
+
+    public static byte[] encode(String str) {
+        MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance("SHA-256");
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+
+        messageDigest.update(str.getBytes());
+        return messageDigest.digest();
+    }
+
+}

+ 45 - 0
src/main/java/cn/com/qmth/ac/util/ServletUtil.java

@@ -0,0 +1,45 @@
+package cn.com.qmth.ac.util;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+public class ServletUtil {
+
+    /**
+     * 获取HttpServletRequest
+     *
+     * @return
+     */
+    public static HttpServletRequest getRequest() {
+        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
+                .getRequestAttributes();
+        return servletRequestAttributes.getRequest();
+    }
+
+    /**
+     * 获取HttpServletResponse
+     *
+     * @return
+     */
+    public static HttpServletResponse getResponse() {
+        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
+                .getRequestAttributes();
+        return servletRequestAttributes.getResponse();
+    }
+
+    /**
+     * 获取HttpServletRequest
+     *
+     * @return
+     */
+    public static HttpSession getSession() {
+        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
+                .getRequestAttributes();
+        return servletRequestAttributes.getRequest().getSession();
+    }
+
+}

+ 31 - 0
src/main/resources/application.properties

@@ -0,0 +1,31 @@
+#
+# ********** server config **********
+#
+server.port=7280
+server.servlet.session.timeout=PT2H
+server.servlet.context-path=/
+spring.servlet.multipart.max-request-size=100MB
+spring.servlet.multipart.max-file-size=100MB
+
+#
+# ********** sys config **********
+#
+com.qmth.logging.root-level=info
+com.qmth.logging.file-path=/home/admin/project/union-question/log/union-question.log
+
+
+spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
+spring.jackson.time-zone=GMT+8
+
+
+
+
+ac.host=https://xxxxxxx
+
+cas.authserver.gdrtvu=https://authserver.ougd.cn/authserver
+cas.authlogin.gdrtvu=https://authserver.ougd.cn/authserver/login
+cas.authlogout.gdrtvu=https://authserver.ougd.cn/authserver/logout
+examcloud.login.gdrtvu=https://gdrtvu.exam-cloud.cn
+examcloud.app-id.gdrtvu=xxxx
+examcloud.root-org-id.gdrtvu=17068
+examcloud.secret-key.gdrtvu=xxxxx