Commit c8f40c0b authored by jiatao's avatar jiatao

Initial commit

parents
target/*
!target/cas-relay-1.0.0.jar
.m2/
*.log
cas-relay.log
cas-relay.out.log
cas-relay.err.log
.idea/
*.iml
README.md
maven-settings.xml
CAS_RELAY_PORT=18080
CAS_SERVICE_URL=https://nercwbs-lms.xidian.edu.cn/orgsso
CAS_SERVER_URL_PREFIX=https://ids.xidian.edu.cn/authserver
CAS_SERVICE_VALIDATE_PATH=/serviceValidate
CAS_LOGIN_PATH=/login
CAS_LOGOUT_PATH=/logout
MINGDAO_ENABLED=true
MINGDAO_REFRESH_ENABLED=true
MINGDAO_REFRESH_INTERVAL_MS=600000
MINGDAO_API_URL=https://nercwbs-lms.xidian.edu.cn/api/v2/open/worksheet/getFilterRows
MINGDAO_APP_KEY=3ed6154939e6aa92
MINGDAO_SIGN=MDM0ZWU1YWM4NzM0ODljZTZiNDJlYmUwYzRmODU4OTNlN2ZkYzIwMjI1ZjBhNzIwZjA4OWU3YzQ1NTdiNGM0Mg==
OAUTH_CLIENT_ID=1506958348348624896
OAUTH_CLIENT_SECRET=19E483DC4D272E4JD5KD
OAUTH_REDIRECT_URI=https://nercwbs-lms.xidian.edu.cn/orgsso/oauth2
OAUTH_AUTHORIZATION_URI=https://ids.xidian.edu.cn/authserver/oauth2.0/authorize
OAUTH_TOKEN_URI=https://ids.xidian.edu.cn/authserver/oauth2.0/accessToken
OAUTH_USER_INFO_URI=https://ids.xidian.edu.cn/authserver/oauthApi/user/profile
OAUTH_USER_MOBILE_URI=https://ids.xidian.edu.cn/authserver/oauthApi/user/getMobile
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ApifoxUploaderProjectSetting">
<option name="apiAccessToken" value="APS-ZFIEhUIIhmBWFFpfNSEZS51Xvbm5L3IU" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="cas-relay" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="cas-relay" options="-parameters" />
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="http://maven.aliyun.com/nexus/content/repositories/central/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="21" project-jdk-type="JavaSDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
FROM openjdk:8
WORKDIR /app
ENV JAVA_OPTS=""
ENV SERVER_PORT=18080
COPY target/cas-relay-1.0.0.jar /app/cas-relay.jar
EXPOSE 18080
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/cas-relay.jar"]
# CAS Relay
一个最小 Java 1.8 / Spring Boot 中转服务,用于明道云 CAS SSO:
1. 服务启动时从明道云教师表分页加载教师信息到内存。
2. 只缓存 `职工号`、`电子邮箱`、`手机号`。
3. 明道云请求本服务并传递 CAS `token` / `ticket`。
4. 本服务请求西电 CAS `serviceValidate` 获取用户工号。
5. 使用工号匹配内存中的教师信息。
6. 匹配成功返回 CAS 标准 XML;匹配失败返回 CAS 标准 failure XML。
## 构建
```bash
mvn -s maven-settings.xml -DskipTests package
```
## Docker 镜像
在仓库根目录执行:
```bash
mvn -s cas-relay/maven-settings.xml -f cas-relay/pom.xml -DskipTests package
docker build -t cas-relay:1.0.0 ./cas-relay
```
本地运行测试:
```bash
docker run --rm -p 18080:18080 \
-e MINGDAO_ENABLED=true \
-e MINGDAO_APP_KEY=your_app_key \
-e MINGDAO_SIGN=your_sign \
-e JAVA_OPTS="-Dcas.service=https://your-mingdao-domain/orgsso" \
cas-relay:1.0.0
```
导出镜像用于上传正式环境:
```bash
docker save cas-relay:1.0.0 -o cas-relay-1.0.0.tar
```
正式环境导入:
```bash
docker load -i cas-relay-1.0.0.tar
```
## Docker Compose 启动
复制环境变量模板:
```bash
cp .env.example .env
```
编辑 `.env`,至少填写:
```bash
CAS_SERVICE_URL=https://你的明道云访问域名/orgsso
MINGDAO_APP_KEY=你的AppKey
MINGDAO_SIGN=你的Sign
```
构建并启动:
```bash
docker compose up -d --build
```
查看日志:
```bash
docker compose logs -f cas-relay
```
停止:
```bash
docker compose down
```
## 明道云 sso.json 示例
示例文件:[sso.example.json](sso.example.json)
关键点:
- `cas.casUrl` 写中转服务公网地址,不写西电 CAS 地址。
- `login`、`logout` 由中转服务重定向到西电 CAS。
- `serviceValidate` 写 `/userinfo`,由中转服务校验 CAS ticket 并补全教师邮箱、手机号。
- Compose 里的 `CAS_SERVICE_URL` 是明道云 `myserviceUrl` 的实际地址,用作明道云未传 `service` 参数时的兜底值。
```json
{
"mode": "common-cas",
"name": "xidian-cas-relay",
"cas": {
"casUrl": "https://your-relay-domain.example.com",
"myserviceUrl": "{HAP}/orgsso",
"serviceValidate": "/userinfo",
"login": "/login",
"logout": "/logout",
"casParams": {
"UserId": "{{&user}}",
"Name": "{{&attributes.cn}}",
"Email": "{{&attributes.mail}}",
"Mobile": "{{&attributes.mobile}}"
},
"autoRegister": true,
"projectId": "your_project_id"
}
}
```
## 明道云 OAuth sso.json 示例
学生 OAuth 对接可使用:[sso.oauth.example.json](sso.oauth.example.json)。
中转服务提供:
- `/oauth2/authorize`:跳转到学校 OAuth 授权地址。
- `/oauth2/access_token`:用 `code` 换上游 `access_token`,再按明道云要求返回 `access_token`。
- `/oauth2/userinfo`:用 `token` 获取学校 profile 中的工号,再用工号查询明道云教师缓存,最后返回带 `data` 包裹的 result 格式。
userinfo 返回示例:
```json
{
"data": {
"uid": "20240001",
"name": "张三",
"email": "20240001@xidian.edu.cn",
"mobilePhone": "13800000000",
"mobile": "13800000000",
"workId": "20240001"
}
}
```
OAuth 的用户资料来源:
- `uid` / `workId`:学校 OAuth profile 返回的 `id`,并要求能匹配明道云教师表职工号。
- `name`:优先取明道云教师表姓名;为空时兜底取学校 profile 的 `attributes.cn`。
- `email`:取明道云教师表电子邮箱。
- `mobilePhone` / `mobile`:取明道云教师表手机号。
如果明道云教师缓存中找不到该工号,`/oauth2/userinfo` 返回失败 result。
对应明道云字段映射:
```json
{
"UserId": "uid",
"Name": "name",
"Email": "email",
"Mobile": "mobilePhone"
}
```
## 启动
生产启动时需要配置明道云授权信息:
```bash
java ^
-DMINGDAO_ENABLED=true ^
-DMINGDAO_APP_KEY=your_app_key ^
-DMINGDAO_SIGN=your_sign ^
-jar target/cas-relay-1.0.0.jar
```
默认端口:`18080`
健康检查:
```http
GET http://localhost:18080/health
```
返回:
```json
{
"status": "UP",
"teacherCount": 1234
}
```
## 明道云用户信息接口
```http
GET http://localhost:18080/userinfo?token={cas_ticket}&service={service}
```
兼容路径:
```http
GET http://localhost:18080/cas/userinfo?ticket={cas_ticket}&service={service}
```
参数说明:
| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `token` / `ticket` | 是 | 明道云传来的 CAS ticket |
| `service` | 否 | CAS 校验所需 service,必须与 ticket 签发时的 service 一致;不传时使用配置项 `cas.service` |
成功返回 CAS XML:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
<cas:authenticationSuccess>
<cas:user>20240001</cas:user>
<cas:attributes>
<cas:employeeNumber>20240001</cas:employeeNumber>
<cas:workNo>20240001</cas:workNo>
<cas:cn>20240001</cas:cn>
<cas:mail>teacher@example.edu.cn</cas:mail>
<cas:email>teacher@example.edu.cn</cas:email>
<cas:mobile>13800000000</cas:mobile>
<cas:phone>13800000000</cas:phone>
</cas:attributes>
</cas:authenticationSuccess>
</cas:serviceResponse>
```
失败返回 CAS XML:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
<cas:authenticationFailure code="USER_NOT_FOUND">teacher not found: 20240001</cas:authenticationFailure>
</cas:serviceResponse>
```
## 明道云教师表配置
配置文件:`src/main/resources/application.yml`
```yaml
mingdao:
enabled: ${MINGDAO_ENABLED:false}
api-url: https://nercwbs-lms.xidian.edu.cn/api/v2/open/worksheet/getFilterRows
app-key: ${MINGDAO_APP_KEY:}
sign: ${MINGDAO_SIGN:}
worksheet-id: 680b5fd8d20405006c858262
view-id: ""
page-size: 1000
list-type: 1
work-no-field: 67b2984de966f87782e24cae
email-field: 67b7cc7e71093078c0201cef
mobile-field: 67b2984de966f87782e24caf
```
启动时会调用:
```http
POST https://nercwbs-lms.xidian.edu.cn/api/v2/open/worksheet/getFilterRows
```
请求中只传入三个字段作为 `controls`:职工号、电子邮箱、手机号。
## 手动刷新教师缓存
```http
POST http://localhost:18080/teachers/refresh
```
用于明道云教师表更新后手动重新加载内存缓存。
## 定时刷新教师缓存
默认每 10 分钟刷新一次明道云教师表缓存:
```env
MINGDAO_REFRESH_ENABLED=true
MINGDAO_REFRESH_INTERVAL_MS=600000
```
如果不需要定时刷新,可以关闭:
```env
MINGDAO_REFRESH_ENABLED=false
```
## 注意事项
- CAS `serviceValidate` 的 `service` 必须与 CAS ticket 签发时使用的 service 完全一致。
- 明道云 `appKey/sign` 不要写死在代码或仓库里,建议使用环境变量、配置中心或密钥管理服务。
- 如果教师表中找不到 CAS 返回的工号,本服务会返回 CAS failure XML,明道云应按登录失败处理。
This diff is collapsed.
services:
cas-relay:
image: cas-relay:1.0.0
build:
context: .
dockerfile: Dockerfile
container_name: cas-relay
restart: unless-stopped
ports:
- "${CAS_RELAY_PORT:-18080}:18080"
environment:
MINGDAO_ENABLED: "${MINGDAO_ENABLED:-true}"
MINGDAO_REFRESH_ENABLED: "${MINGDAO_REFRESH_ENABLED:-true}"
MINGDAO_REFRESH_INTERVAL_MS: "${MINGDAO_REFRESH_INTERVAL_MS:-600000}"
MINGDAO_APP_KEY: "${MINGDAO_APP_KEY}"
MINGDAO_SIGN: "${MINGDAO_SIGN}"
JAVA_OPTS: >-
-Dcas.service=${CAS_SERVICE_URL}
-Dcas.server-url-prefix=${CAS_SERVER_URL_PREFIX:-https://ids.xidian.edu.cn/authserver}
-Dcas.service-validate-path=${CAS_SERVICE_VALIDATE_PATH:-/serviceValidate}
-Dcas.login-path=${CAS_LOGIN_PATH:-/login}
-Dcas.logout-path=${CAS_LOGOUT_PATH:-/logout}
-Dmingdao.api-url=${MINGDAO_API_URL:-https://nercwbs-lms.xidian.edu.cn/api/v2/open/worksheet/getFilterRows}
-Doauth-relay.client-id=${OAUTH_CLIENT_ID:-}
-Doauth-relay.client-secret=${OAUTH_CLIENT_SECRET:-}
-Doauth-relay.redirect-uri=${OAUTH_REDIRECT_URI:-}
-Doauth-relay.authorization-uri=${OAUTH_AUTHORIZATION_URI:-https://ids.xidian.edu.cn/authserver/oauth2.0/authorize}
-Doauth-relay.token-uri=${OAUTH_TOKEN_URI:-https://ids.xidian.edu.cn/authserver/oauth2.0/accessToken}
-Doauth-relay.user-info-uri=${OAUTH_USER_INFO_URI:-https://ids.xidian.edu.cn/authserver/oauthApi/user/profile}
-Doauth-relay.user-mobile-uri=${OAUTH_USER_MOBILE_URI:-https://ids.xidian.edu.cn/authserver/oauthApi/user/getMobile}
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<localRepository>C:/usr/code/java/jd_easywalk/.m2/repository</localRepository>
</settings>
<?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>com.jd.easywalk</groupId>
<artifactId>cas-relay</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>cas-relay</name>
<description>CAS user info relay service for Mingdao SSO</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.15</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.jd.easywalk.casrelay;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableConfigurationProperties({CasRelayProperties.class, MingdaoProperties.class, OAuthRelayProperties.class})
public class CasRelayApplication {
public static void main(String[] args) {
SpringApplication.run(CasRelayApplication.class, args);
}
}
package com.jd.easywalk.casrelay;
import java.util.LinkedHashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.util.UriComponentsBuilder;
@RestController
public class CasRelayController {
private static final Logger log = LoggerFactory.getLogger(CasRelayController.class);
private final CasRelayService casRelayService;
private final TeacherDirectoryService teacherDirectoryService;
private final CasRelayProperties casRelayProperties;
public CasRelayController(CasRelayService casRelayService, TeacherDirectoryService teacherDirectoryService,
CasRelayProperties casRelayProperties) {
this.casRelayService = casRelayService;
this.teacherDirectoryService = teacherDirectoryService;
this.casRelayProperties = casRelayProperties;
}
@GetMapping({"/health", "/actuator/health"})
public Map<String, Object> health() {
Map<String, Object> body = new LinkedHashMap<String, Object>();
body.put("status", "UP");
body.put("teacherCount", teacherDirectoryService.size());
return body;
}
@PostMapping("/teachers/refresh")
public Map<String, Object> refreshTeachers() {
teacherDirectoryService.refresh();
Map<String, Object> body = new LinkedHashMap<String, Object>();
body.put("success", true);
body.put("teacherCount", teacherDirectoryService.size());
return body;
}
@RequestMapping("/login")
public RedirectView login(@RequestParam Map<String, String> params) {
String redirectUrl = buildCasUrl(casRelayProperties.getLoginPath(), params);
log.info("CAS relay login redirect: target={}", redirectUrl);
return redirectView(redirectUrl);
}
@RequestMapping("/logout")
public RedirectView logout(@RequestParam Map<String, String> params) {
String redirectUrl = buildCasUrl(casRelayProperties.getLogoutPath(), params);
log.info("CAS relay logout redirect: target={}", redirectUrl);
return redirectView(redirectUrl);
}
@GetMapping(value = {"/userinfo", "/cas/userinfo"}, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<String> userInfo(
@RequestParam(required = false) String token,
@RequestParam(required = false) String ticket,
@RequestParam(required = false) String service) {
String casTicket = StringUtils.hasText(token) ? token : ticket;
log.info("Mingdao CAS relay request received: hasToken={}, hasTicket={}, ticket={}, service={}",
StringUtils.hasText(token), StringUtils.hasText(ticket), maskTicket(casTicket), service);
if (!StringUtils.hasText(casTicket)) {
log.warn("Mingdao CAS relay request rejected: token or ticket is empty");
return ResponseEntity.badRequest()
.contentType(MediaType.APPLICATION_XML)
.body(casRelayService.failureXml("INVALID_REQUEST", "token or ticket is required"));
}
String xml = casRelayService.getUserInfoXml(casTicket, service);
log.info("Mingdao CAS relay response generated: ticket={}, xmlLength={}", maskTicket(casTicket), xml.length());
return ResponseEntity.ok().contentType(MediaType.APPLICATION_XML).body(xml);
}
private String maskTicket(String value) {
if (!StringUtils.hasText(value)) {
return "";
}
if (value.length() <= 12) {
return value.substring(0, Math.min(value.length(), 4)) + "***";
}
return value.substring(0, 6) + "***" + value.substring(value.length() - 6);
}
private String buildCasUrl(String path, Map<String, String> params) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl(trimTrailingSlash(casRelayProperties.getServerUrlPrefix()) + normalizePath(path));
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.queryParam(entry.getKey(), entry.getValue());
}
return builder.build().toUriString();
}
private RedirectView redirectView(String redirectUrl) {
RedirectView redirectView = new RedirectView(redirectUrl);
redirectView.setExpandUriTemplateVariables(false);
return redirectView;
}
private String trimTrailingSlash(String value) {
if (value == null) {
return "";
}
return value.endsWith("/") ? value.substring(0, value.length() - 1) : value;
}
private String normalizePath(String value) {
if (!StringUtils.hasText(value)) {
return "";
}
return value.startsWith("/") ? value : "/" + value;
}
}
package com.jd.easywalk.casrelay;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "cas")
public class CasRelayProperties {
private String serverUrlPrefix = "https://ids.xidian.edu.cn/authserver";
private String serviceValidatePath = "/serviceValidate";
private String loginPath = "/login";
private String logoutPath = "/logout";
private String service = "http://localhost:18080/userinfo";
private int connectTimeoutMs = 5000;
private int readTimeoutMs = 10000;
public String getServerUrlPrefix() {
return serverUrlPrefix;
}
public void setServerUrlPrefix(String serverUrlPrefix) {
this.serverUrlPrefix = serverUrlPrefix;
}
public String getServiceValidatePath() {
return serviceValidatePath;
}
public void setServiceValidatePath(String serviceValidatePath) {
this.serviceValidatePath = serviceValidatePath;
}
public String getLoginPath() {
return loginPath;
}
public void setLoginPath(String loginPath) {
this.loginPath = loginPath;
}
public String getLogoutPath() {
return logoutPath;
}
public void setLogoutPath(String logoutPath) {
this.logoutPath = logoutPath;
}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public int getConnectTimeoutMs() {
return connectTimeoutMs;
}
public void setConnectTimeoutMs(int connectTimeoutMs) {
this.connectTimeoutMs = connectTimeoutMs;
}
public int getReadTimeoutMs() {
return readTimeoutMs;
}
public void setReadTimeoutMs(int readTimeoutMs) {
this.readTimeoutMs = readTimeoutMs;
}
}
This diff is collapsed.
package com.jd.easywalk.casrelay;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "mingdao")
public class MingdaoProperties {
private boolean enabled = false;
private boolean refreshEnabled = true;
private long refreshIntervalMs = 600000L;
private String apiUrl = "https://nercwbs-lms.xidian.edu.cn/api/v2/open/worksheet/getFilterRows";
private String appKey = "";
private String sign = "";
private String worksheetId = "680b5fd8d20405006c858262";
private String viewId = "";
private int pageSize = 1000;
private int listType = 1;
private String nameField = "67b2981fe966f87782e24aa9";
private String workNoField = "67b2984de966f87782e24cae";
private String emailField = "67b7cc7e71093078c0201cef";
private String mobileField = "67b2984de966f87782e24caf";
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isRefreshEnabled() {
return refreshEnabled;
}
public void setRefreshEnabled(boolean refreshEnabled) {
this.refreshEnabled = refreshEnabled;
}
public long getRefreshIntervalMs() {
return refreshIntervalMs;
}
public void setRefreshIntervalMs(long refreshIntervalMs) {
this.refreshIntervalMs = refreshIntervalMs;
}
public String getApiUrl() {
return apiUrl;
}
public void setApiUrl(String apiUrl) {
this.apiUrl = apiUrl;
}
public String getAppKey() {
return appKey;
}
public void setAppKey(String appKey) {
this.appKey = appKey;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getWorksheetId() {
return worksheetId;
}
public void setWorksheetId(String worksheetId) {
this.worksheetId = worksheetId;
}
public String getViewId() {
return viewId;
}
public void setViewId(String viewId) {
this.viewId = viewId;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getListType() {
return listType;
}
public void setListType(int listType) {
this.listType = listType;
}
public String getNameField() {
return nameField;
}
public void setNameField(String nameField) {
this.nameField = nameField;
}
public String getWorkNoField() {
return workNoField;
}
public void setWorkNoField(String workNoField) {
this.workNoField = workNoField;
}
public String getEmailField() {
return emailField;
}
public void setEmailField(String emailField) {
this.emailField = emailField;
}
public String getMobileField() {
return mobileField;
}
public void setMobileField(String mobileField) {
this.mobileField = mobileField;
}
}
package com.jd.easywalk.casrelay;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.RedirectView;
@RestController
@RequestMapping("/oauth2")
public class OAuthRelayController {
private static final Logger log = LoggerFactory.getLogger(OAuthRelayController.class);
private final OAuthRelayService oauthRelayService;
public OAuthRelayController(OAuthRelayService oauthRelayService) {
this.oauthRelayService = oauthRelayService;
}
@GetMapping({"/authorize", "/login"})
public RedirectView authorize(@RequestParam Map<String, String> params) {
String target = oauthRelayService.buildAuthorizationRedirect(params);
log.info("OAuth relay authorize request: params={}, target={}", params, target);
return new RedirectView(target);
}
@PostMapping({"/access_token", "/token"})
public ResponseEntity<Map<String, Object>> accessToken(@RequestParam Map<String, String> params) {
log.info("OAuth relay token request received: grantType={}, hasCode={}, redirectUri={}",
params.get("grant_type"), StringUtils.hasText(params.get("code")), params.get("redirect_uri"));
return ResponseEntity.ok(oauthRelayService.exchangeToken(params));
}
@GetMapping({"/userinfo", "/user_info"})
public ResponseEntity<Map<String, Object>> userInfo(
@RequestParam(required = false) String token,
@RequestParam(required = false) String access_token) {
String realToken = StringUtils.hasText(token) ? token : access_token;
log.info("OAuth relay Mingdao userInfo request received: hasToken={}, hasAccessToken={}",
StringUtils.hasText(token), StringUtils.hasText(access_token));
return ResponseEntity.ok(oauthRelayService.userInfo(realToken));
}
}
package com.jd.easywalk.casrelay;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "oauth-relay")
public class OAuthRelayProperties {
private boolean enabled = true;
private String clientId = "";
private String clientSecret = "";
private String authorizationUri = "https://ids.xidian.edu.cn/authserver/oauth2.0/authorize";
private String tokenUri = "https://ids.xidian.edu.cn/authserver/oauth2.0/accessToken";
private String userInfoUri = "https://ids.xidian.edu.cn/authserver/oauthApi/user/profile";
private String userMobileUri = "https://ids.xidian.edu.cn/authserver/oauthApi/user/getMobile";
private String redirectUri = "";
private int expiresIn = 7200;
private String emailDomain = "xidian.edu.cn";
private boolean synthesizeEmail = true;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getAuthorizationUri() {
return authorizationUri;
}
public void setAuthorizationUri(String authorizationUri) {
this.authorizationUri = authorizationUri;
}
public String getTokenUri() {
return tokenUri;
}
public void setTokenUri(String tokenUri) {
this.tokenUri = tokenUri;
}
public String getUserInfoUri() {
return userInfoUri;
}
public void setUserInfoUri(String userInfoUri) {
this.userInfoUri = userInfoUri;
}
public String getUserMobileUri() {
return userMobileUri;
}
public void setUserMobileUri(String userMobileUri) {
this.userMobileUri = userMobileUri;
}
public String getRedirectUri() {
return redirectUri;
}
public void setRedirectUri(String redirectUri) {
this.redirectUri = redirectUri;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
public String getEmailDomain() {
return emailDomain;
}
public void setEmailDomain(String emailDomain) {
this.emailDomain = emailDomain;
}
public boolean isSynthesizeEmail() {
return synthesizeEmail;
}
public void setSynthesizeEmail(boolean synthesizeEmail) {
this.synthesizeEmail = synthesizeEmail;
}
}
This diff is collapsed.
package com.jd.easywalk.casrelay;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
@Service
public class TeacherDirectoryService {
private static final Logger log = LoggerFactory.getLogger(TeacherDirectoryService.class);
private final MingdaoProperties properties;
private final RestTemplate restTemplate;
private final Map<String, TeacherInfo> teachersByWorkNo = new ConcurrentHashMap<String, TeacherInfo>();
public TeacherDirectoryService(MingdaoProperties properties, RestTemplateBuilder restTemplateBuilder) {
this.properties = properties;
this.restTemplate = restTemplateBuilder.build();
}
@PostConstruct
public void loadOnStartup() {
if (!properties.isEnabled()) {
log.info("Mingdao teacher directory loading is disabled");
return;
}
refresh();
}
public synchronized void refresh() {
validateConfig();
Map<String, TeacherInfo> loaded = new HashMap<String, TeacherInfo>();
int pageIndex = 1;
int pageSize = Math.max(properties.getPageSize(), 1);
while (true) {
Map<String, Object> response = fetchPage(pageIndex, pageSize);
if (!Boolean.TRUE.equals(response.get("success"))) {
throw new IllegalStateException("Mingdao worksheet request failed: " + response);
}
List<Map<String, Object>> rows = extractRows(response);
for (Map<String, Object> row : rows) {
TeacherInfo teacher = toTeacherInfo(row);
if (teacher != null) {
loaded.put(teacher.getWorkNo(), teacher);
}
}
if (rows.size() < pageSize) {
break;
}
pageIndex++;
}
teachersByWorkNo.clear();
teachersByWorkNo.putAll(loaded);
log.info("Loaded {} teachers from Mingdao worksheet", teachersByWorkNo.size());
logTeacherDetails();
}
public TeacherInfo findByWorkNo(String workNo) {
if (!StringUtils.hasText(workNo)) {
return null;
}
return teachersByWorkNo.get(workNo.trim());
}
public int size() {
return teachersByWorkNo.size();
}
@Scheduled(fixedDelayString = "${mingdao.refresh-interval-ms:600000}")
public void scheduledRefresh() {
if (!properties.isEnabled() || !properties.isRefreshEnabled()) {
return;
}
try {
log.info("Scheduled Mingdao teacher directory refresh started");
refresh();
log.info("Scheduled Mingdao teacher directory refresh finished, teacherCount={}", size());
} catch (Exception ex) {
log.error("Scheduled Mingdao teacher directory refresh failed", ex);
}
}
private Map<String, Object> fetchPage(int pageIndex, int pageSize) {
Map<String, Object> request = new LinkedHashMap<String, Object>();
request.put("appKey", properties.getAppKey());
request.put("sign", properties.getSign());
request.put("worksheetId", properties.getWorksheetId());
request.put("viewId", properties.getViewId());
request.put("pageSize", pageSize);
request.put("pageIndex", pageIndex);
request.put("listType", properties.getListType());
request.put("controls", selectedControls());
request.put("notGetTotal", true);
request.put("useControlId", true);
request.put("getSystemControl", false);
return restTemplate.postForObject(properties.getApiUrl(), request, Map.class);
}
private List<String> selectedControls() {
List<String> controls = new ArrayList<String>();
controls.add(properties.getNameField());
controls.add(properties.getWorkNoField());
controls.add(properties.getEmailField());
controls.add(properties.getMobileField());
return controls;
}
private List<Map<String, Object>> extractRows(Map<String, Object> response) {
Object data = response.get("data");
if (!(data instanceof Map)) {
return Collections.emptyList();
}
Object rows = ((Map<?, ?>) data).get("rows");
if (!(rows instanceof List)) {
return Collections.emptyList();
}
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
for (Object row : (List<?>) rows) {
if (row instanceof Map) {
result.add((Map<String, Object>) row);
}
}
return result;
}
private TeacherInfo toTeacherInfo(Map<String, Object> row) {
String workNo = value(row, properties.getWorkNoField(), "workNo", "UserId");
if (!StringUtils.hasText(workNo)) {
return null;
}
String name = value(row, properties.getNameField(), "name", "Name");
String email = value(row, properties.getEmailField(), "email", "Email");
String mobile = value(row, properties.getMobileField(), "mobile", "Mobile");
return new TeacherInfo(workNo.trim(), trim(name), trim(email), trim(mobile));
}
private String value(Map<String, Object> row, String... keys) {
for (String key : keys) {
Object value = row.get(key);
if (value instanceof Map) {
value = ((Map<?, ?>) value).get("value");
}
if (value != null && StringUtils.hasText(String.valueOf(value))) {
return String.valueOf(value);
}
}
return null;
}
private String trim(String value) {
return value == null ? null : value.trim();
}
private void validateConfig() {
if (!StringUtils.hasText(properties.getAppKey())) {
throw new IllegalStateException("mingdao.app-key is required");
}
if (!StringUtils.hasText(properties.getSign())) {
throw new IllegalStateException("mingdao.sign is required");
}
if (!StringUtils.hasText(properties.getWorksheetId())) {
throw new IllegalStateException("mingdao.worksheet-id is required");
}
}
private void logTeacherDetails() {
for (TeacherInfo teacher : teachersByWorkNo.values()) {
log.info("Cached teacher: workNo={}, name={}, email={}, mobile={}",
teacher.getWorkNo(), teacher.getName(), teacher.getEmail(), teacher.getMobile());
}
}
}
package com.jd.easywalk.casrelay;
public class TeacherInfo {
private final String workNo;
private final String name;
private final String email;
private final String mobile;
public TeacherInfo(String workNo, String name, String email, String mobile) {
this.workNo = workNo;
this.name = name;
this.email = email;
this.mobile = mobile;
}
public String getWorkNo() {
return workNo;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getMobile() {
return mobile;
}
}
server:
port: 18080
cas:
server-url-prefix: https://ids.xidian.edu.cn/authserver
service-validate-path: /serviceValidate
login-path: /login
logout-path: /logout
# CAS service must match the service value used when the ticket was issued.
# Mingdao can pass service in the request; this value is the fallback.
service: http://localhost:18080/userinfo
connect-timeout-ms: 5000
read-timeout-ms: 10000
mingdao:
enabled: ${MINGDAO_ENABLED:true}
refresh-enabled: ${MINGDAO_REFRESH_ENABLED:true}
refresh-interval-ms: ${MINGDAO_REFRESH_INTERVAL_MS:600000}
api-url: https://nercwbs-lms.xidian.edu.cn/api/v2/open/worksheet/getFilterRows
app-key: ${MINGDAO_APP_KEY:3ed6154939e6aa92}
sign: ${MINGDAO_SIGN:MDM0ZWU1YWM4NzM0ODljZTZiNDJlYmUwYzRmODU4OTNlN2ZkYzIwMjI1ZjBhNzIwZjA4OWU3YzQ1NTdiNGM0Mg==}
worksheet-id: 680b5fd8d20405006c858262
view-id: ""
page-size: 1000
# 1 means return all rows in table format according to Mingdao docs.
list-type: 1
# Teacher worksheet controls.
name-field: 67b2981fe966f87782e24aa9
work-no-field: 67b2984de966f87782e24cae
email-field: 67b7cc7e71093078c0201cef
mobile-field: 67b2984de966f87782e24caf
oauth-relay:
enabled: ${OAUTH_RELAY_ENABLED:true}
client-id: ${OAUTH_CLIENT_ID:1506958348348624896}
client-secret: ${OAUTH_CLIENT_SECRET:19E483DC4D272E4JD5KD}
authorization-uri: ${OAUTH_AUTHORIZATION_URI:https://ids.xidian.edu.cn/authserver/oauth2.0/authorize}
token-uri: ${OAUTH_TOKEN_URI:https://ids.xidian.edu.cn/authserver/oauth2.0/accessToken}
user-info-uri: ${OAUTH_USER_INFO_URI:https://ids.xidian.edu.cn/authserver/oauthApi/user/profile}
user-mobile-uri: ${OAUTH_USER_MOBILE_URI:https://ids.xidian.edu.cn/authserver/oauthApi/user/getMobile}
redirect-uri: ${OAUTH_REDIRECT_URI:}
expires-in: ${OAUTH_EXPIRES_IN:7200}
email-domain: ${OAUTH_EMAIL_DOMAIN:xidian.edu.cn}
synthesize-email: ${OAUTH_SYNTHESIZE_EMAIL:true}
{
"mode": "common-cas",
"name": "cas",
"cas": {
"casUrl": "http://222.25.179.53:18080",
"myserviceUrl": "https://nercwbs-lms.xidian.edu.cn/orgsso",
"serviceValidate": "/userinfo",
"login": "/login",
"logout": "/logout",
"casParams": {
"UserId": "{{&user}}",
"Name": "{{&attributes.cn}}",
"Email": "{{&attributes.mail}}",
"Mobile": "{{&attributes.mobile}}"
},
"projectId": "22070640-479c-493b-9045-9c39e303cf2a"
}
}
{
"mode": "common-oauth2",
"name": "xidian-oauth-relay",
"oauth2": {
"oauth2Url": "https://your-relay-domain.example.com",
"clientId": "relay-client",
"clientSecret": "relay-secret",
"idParamName": "client_id",
"secretParamName": "client_secret",
"accessTokenParamName": "access_token",
"redirectUri": "{HAP}/orgsso/oauth2",
"authorizePath": "/oauth2/authorize",
"tokenPath": "/oauth2/access_token",
"userInfoUrl": "https://your-relay-domain.example.com/oauth2/userinfo",
"tokenKeyParamName": "token",
"authorizationMethod": "body",
"bodyFormat": "form",
"scope": "",
"params": {
"UserId": "uid",
"Name": "name",
"Email": "email",
"Mobile": "mobilePhone"
},
"autoRegister": true,
"projectId": "your_project_id"
}
}
{
"groups": [
{
"name": "cas",
"type": "com.jd.easywalk.casrelay.CasRelayProperties",
"sourceType": "com.jd.easywalk.casrelay.CasRelayProperties"
},
{
"name": "mingdao",
"type": "com.jd.easywalk.casrelay.MingdaoProperties",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties"
},
{
"name": "oauth-relay",
"type": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties"
}
],
"properties": [
{
"name": "cas.connect-timeout-ms",
"type": "java.lang.Integer",
"sourceType": "com.jd.easywalk.casrelay.CasRelayProperties",
"defaultValue": 5000
},
{
"name": "cas.login-path",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.CasRelayProperties",
"defaultValue": "\/login"
},
{
"name": "cas.logout-path",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.CasRelayProperties",
"defaultValue": "\/logout"
},
{
"name": "cas.read-timeout-ms",
"type": "java.lang.Integer",
"sourceType": "com.jd.easywalk.casrelay.CasRelayProperties",
"defaultValue": 10000
},
{
"name": "cas.server-url-prefix",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.CasRelayProperties",
"defaultValue": "https:\/\/ids.xidian.edu.cn\/authserver"
},
{
"name": "cas.service",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.CasRelayProperties",
"defaultValue": "http:\/\/localhost:18080\/userinfo"
},
{
"name": "cas.service-validate-path",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.CasRelayProperties",
"defaultValue": "\/serviceValidate"
},
{
"name": "mingdao.api-url",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": "https:\/\/nercwbs-lms.xidian.edu.cn\/api\/v2\/open\/worksheet\/getFilterRows"
},
{
"name": "mingdao.app-key",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": ""
},
{
"name": "mingdao.email-field",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": "67b7cc7e71093078c0201cef"
},
{
"name": "mingdao.enabled",
"type": "java.lang.Boolean",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": false
},
{
"name": "mingdao.list-type",
"type": "java.lang.Integer",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": 1
},
{
"name": "mingdao.mobile-field",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": "67b2984de966f87782e24caf"
},
{
"name": "mingdao.name-field",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": "67b2981fe966f87782e24aa9"
},
{
"name": "mingdao.page-size",
"type": "java.lang.Integer",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": 1000
},
{
"name": "mingdao.refresh-enabled",
"type": "java.lang.Boolean",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": true
},
{
"name": "mingdao.refresh-interval-ms",
"type": "java.lang.Long",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": 600000
},
{
"name": "mingdao.sign",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": ""
},
{
"name": "mingdao.view-id",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": ""
},
{
"name": "mingdao.work-no-field",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": "67b2984de966f87782e24cae"
},
{
"name": "mingdao.worksheet-id",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.MingdaoProperties",
"defaultValue": "680b5fd8d20405006c858262"
},
{
"name": "oauth-relay.authorization-uri",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": "https:\/\/ids.xidian.edu.cn\/authserver\/oauth2.0\/authorize"
},
{
"name": "oauth-relay.client-id",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": ""
},
{
"name": "oauth-relay.client-secret",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": ""
},
{
"name": "oauth-relay.email-domain",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": "xidian.edu.cn"
},
{
"name": "oauth-relay.enabled",
"type": "java.lang.Boolean",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": true
},
{
"name": "oauth-relay.expires-in",
"type": "java.lang.Integer",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": 7200
},
{
"name": "oauth-relay.redirect-uri",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": ""
},
{
"name": "oauth-relay.synthesize-email",
"type": "java.lang.Boolean",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": true
},
{
"name": "oauth-relay.token-uri",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": "https:\/\/ids.xidian.edu.cn\/authserver\/oauth2.0\/accessToken"
},
{
"name": "oauth-relay.user-info-uri",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": "https:\/\/ids.xidian.edu.cn\/authserver\/oauthApi\/user\/profile"
},
{
"name": "oauth-relay.user-mobile-uri",
"type": "java.lang.String",
"sourceType": "com.jd.easywalk.casrelay.OAuthRelayProperties",
"defaultValue": "https:\/\/ids.xidian.edu.cn\/authserver\/oauthApi\/user\/getMobile"
}
],
"hints": []
}
\ No newline at end of file
server:
port: 18080
cas:
server-url-prefix: https://ids.xidian.edu.cn/authserver
service-validate-path: /serviceValidate
login-path: /login
logout-path: /logout
# CAS service must match the service value used when the ticket was issued.
# Mingdao can pass service in the request; this value is the fallback.
service: http://localhost:18080/userinfo
connect-timeout-ms: 5000
read-timeout-ms: 10000
mingdao:
enabled: ${MINGDAO_ENABLED:true}
refresh-enabled: ${MINGDAO_REFRESH_ENABLED:true}
refresh-interval-ms: ${MINGDAO_REFRESH_INTERVAL_MS:600000}
api-url: https://nercwbs-lms.xidian.edu.cn/api/v2/open/worksheet/getFilterRows
app-key: ${MINGDAO_APP_KEY:3ed6154939e6aa92}
sign: ${MINGDAO_SIGN:MDM0ZWU1YWM4NzM0ODljZTZiNDJlYmUwYzRmODU4OTNlN2ZkYzIwMjI1ZjBhNzIwZjA4OWU3YzQ1NTdiNGM0Mg==}
worksheet-id: 680b5fd8d20405006c858262
view-id: ""
page-size: 1000
# 1 means return all rows in table format according to Mingdao docs.
list-type: 1
# Teacher worksheet controls.
name-field: 67b2981fe966f87782e24aa9
work-no-field: 67b2984de966f87782e24cae
email-field: 67b7cc7e71093078c0201cef
mobile-field: 67b2984de966f87782e24caf
oauth-relay:
enabled: ${OAUTH_RELAY_ENABLED:true}
client-id: ${OAUTH_CLIENT_ID:1506958348348624896}
client-secret: ${OAUTH_CLIENT_SECRET:19E483DC4D272E4JD5KD}
authorization-uri: ${OAUTH_AUTHORIZATION_URI:https://ids.xidian.edu.cn/authserver/oauth2.0/authorize}
token-uri: ${OAUTH_TOKEN_URI:https://ids.xidian.edu.cn/authserver/oauth2.0/accessToken}
user-info-uri: ${OAUTH_USER_INFO_URI:https://ids.xidian.edu.cn/authserver/oauthApi/user/profile}
user-mobile-uri: ${OAUTH_USER_MOBILE_URI:https://ids.xidian.edu.cn/authserver/oauthApi/user/getMobile}
redirect-uri: ${OAUTH_REDIRECT_URI:}
expires-in: ${OAUTH_EXPIRES_IN:7200}
email-domain: ${OAUTH_EMAIL_DOMAIN:xidian.edu.cn}
synthesize-email: ${OAUTH_SYNTHESIZE_EMAIL:true}
artifactId=cas-relay
groupId=com.jd.easywalk
version=1.0.0
com\jd\easywalk\casrelay\MingdaoProperties.class
com\jd\easywalk\casrelay\CasRelayApplication.class
com\jd\easywalk\casrelay\OAuthRelayController.class
com\jd\easywalk\casrelay\OAuthRelayProperties.class
com\jd\easywalk\casrelay\OAuthRelayService$1.class
META-INF\spring-configuration-metadata.json
com\jd\easywalk\casrelay\CasRelayProperties.class
com\jd\easywalk\casrelay\TeacherInfo.class
com\jd\easywalk\casrelay\CasRelayService.class
com\jd\easywalk\casrelay\CasRelayController.class
com\jd\easywalk\casrelay\OAuthRelayService.class
com\jd\easywalk\casrelay\TeacherDirectoryService.class
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\CasRelayProperties.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\OAuthRelayService.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\TeacherInfo.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\OAuthRelayProperties.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\CasRelayService.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\MingdaoProperties.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\CasRelayApplication.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\OAuthRelayController.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\TeacherDirectoryService.java
C:\usr\code\java\jd_easywalk\cas-relay\src\main\java\com\jd\easywalk\casrelay\CasRelayController.java
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment