对接达实授权平台
对接达实授权平台
::: caution
在对接开放平台之前,您需要先了解一些前置知识,这些内容是对接开放平台的基础
:::
1. 场景
客户有自己统一的认证中心,在认证中心登录后就可以直接进入达实系统;认证中心退出的同时达实也会退出。
2. 适用版本
AIOT V6
3. 功能介绍
3.1单点登录介绍
单点登录(single sign on),简称SSO,用户只需登录一次统一认证系统,就可访问同一帐号平台下的多个应用系统。
3.1.1. 实现机制
1、当用户第一次访问应用系统(达实)的时候,因为还没有登录,会被引导到认证系统中进行登录;根据用户提供的登录信息,认证系统进行身份校验,如果通过校验,返回给用户一个认证的凭据。
2、用户从认证系统跳转到应用系统的时候,就会将这个认证的凭据带上,应用系统接受到请求之后会把认证的凭据通过接口传输给认证系统进行校验,检查认证的凭据的合法性。如果通过校验,用户就可以开始访问应用系统。
如图:
3.1.1. 实现条件
实现SSO,需要以下主要的功能:
认证系统:用户进行登录认证;认证成功后,认证系统生成统一的认证凭据,返还给用户;认证系统对认证凭据进行校验,判断其有效性。
应用系统:通过与认证系统的对接,将用户的认证凭据传输到认证系统进行认证,从而实现对认证凭据进行识别和获取用户信息,返回认证结果从而完成单点登录的功能。
SSO插件:现场二开编写插件实现上述应用系统对接认证系统的功能,开发文档参考单点登录插件开发说明。
3.2 单点登录插件开发说明
3.2.1 方式一:采用依赖SDK的方式
依赖达实SDK
<dependency>
<groupId>com.das</groupId>
<artifactId>portal-login</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
可以提供Jar包,该工具包实现对接达实授权平台
application.yml需要增加配置:
justauth:
# 开启oauth2协议
enabled: true
extend:
# 自定义资源配置
enum-class: com.das.aiot.portal.login.extend.ExtendSource
config:
# 达实
DAS:
# 达实接口配置类
request-class: com.das.aiot.portal.login.extend.ExtendDASRequest
# clientId
client-id: 单点登录配置的凭证ID
# clientSecret
client-secret: 单点登录配置的凭证密钥
# 回调地址。获取到获取码后回调的链接
redirect-uri: 单点登录配置的回调地址
# scope
scopes:
- sever
com.das.aiot.portal.login.extend.ExtendSource -- oauth2协议配置自定义资源类
com.das.aiot.portal.login.extend.ExtendDASRequest -- 达实接口配置类
推荐接口:
com.das.aiot.portal.login.controller.LoginController#login(String,HttpServletResponse) -- 获取授权码
com.das.aiot.portal.login.controller.LoginController#login(String,AuthCallback) -- 使用授权码获取token
com.das.aiot.portal.login.controller.LoginController#refresh -- 刷新token
3.2.2 方式二:自定义对接
3.2.2.1 POM依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.0.4</version>
</dependency>
<!-- 对象池,使用redis时必须引入 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>5.8.15</version>
</dependency>
<dependency>
<groupId>com.xkcoding.justauth</groupId>
<artifactId>justauth-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<optional>true</optional>
</dependency>
3.2.2.2 声明达实接口配置
public enum ExtendSource implements AuthSource {
/**
* 达实
*/
DAS {
/**
* 授权的api
*
* @return url
*/
@Override
public String authorize() {
return "http://kingdeedemo.rd.chn-das.com/api/justauth/oauth-server/v1/visitor/oauth/authorize";
}
/**
* 获取accessToken的api
*
* @return url
*/
@Override
public String accessToken() {
return "http://kingdeedemo.rd.chn-das.com/api/justauth/oauth-server/v1/visitor/oauth/token";
}
/**
* 刷新授权的api
*
* @return url
*/
@Override
public String refresh() {
return "http://kingdeedemo.rd.chn-das.com/api/justauth/oauth-server/v1/visitor/oauth/token";
}
}
}
达实登录相关接口
3.2.2.3 达实接口扩展处理类
作用:达实接口对接时的扩展处理。 可增加自定义参数、自定义返回值
public class ExtendDASRequest extends AuthDefaultRequest {
public ExtendDASRequest(AuthConfig config) {
super(config, ExtendSource.DAS);
}
public ExtendDASRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, ExtendSource.DAS, authStateCache);
}
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(super.authorize(state))
.queryParam("scope", this.getScopes("+", false, AuthScopeUtils.getDefaultScopes(AuthGitlabScope.values())))
.build();
}
/**
* 获取access token
*
* @param authCallback 授权成功后的回调参数
* @return token
* @see AuthDefaultRequest#authorize()
* @see AuthDefaultRequest#authorize(String)
*/
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
String response = doPostAuthorizationCode(authCallback.getCode());
JSONObject object = JSONObject.parseObject(response);
return AuthToken.builder()
.accessToken(object.getString(JWTConstant.ACCESS_TOKEN))
.refreshToken(object.getString(JWTConstant.REFRESH_TOKEN))
.scope(object.getString(JWTConstant.SCOPE))
.screenName(object.getString(JWTConstant.NAME))
.userId(object.getString(JWTConstant.SUB))
.tokenType(object.getString(JWTConstant.TOKEN_TYPE))
.expireIn(object.getInteger(JWTConstant.EXPIRES_IN))
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
return null;
}
/**
* 刷新access token (续期)
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
@Override
public AuthResponse refresh(AuthToken authToken) {
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(getToken(refreshTokenUrl(authToken.getRefreshToken())))
.build();
}
private AuthToken getToken(String accessTokenUrl) {
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl);
JSONObject accessTokenObject = JSONObject.parseObject(response);
return AuthToken.builder()
.accessToken(accessTokenObject.getString(JWTConstant.ACCESS_TOKEN))
.refreshToken(accessTokenObject.getString(JWTConstant.REFRESH_TOKEN))
.scope(accessTokenObject.getString(JWTConstant.SCOPE))
.screenName(accessTokenObject.getString(JWTConstant.NAME))
.userId(accessTokenObject.getString(JWTConstant.SUB))
.tokenType(accessTokenObject.getString(JWTConstant.TOKEN_TYPE))
.expireIn(accessTokenObject.getInteger(JWTConstant.EXPIRES_IN))
.build();
}
}
3.2.2.4 接口demo Service
可参考该service自定义controller。或者额外的逻辑处理
@Service
@RequiredArgsConstructor
@Slf4j
public class LoginServiceImpl implements ILoginService {
private final AuthRequestFactory factory;
@Override
public List<String> oauthList() {
return factory.oauthList();
}
/**
* 登录第三方的接口
*
* @param type 第三方类型
* @param response 响应
* @return: {@link Void}
* @throws:
*/
@Override
public void login(String type, HttpServletResponse response) throws IOException {
AuthRequest authRequest = factory.get(type);
response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
}
/**
* 登录第三方是的回调地址 接口
*
* @param type 第三方类型
* @param callback 接收到的授权码
* @return: {@link TokenDTO}
* @throws:
*/
@Override
public TokenDTO loginCallback(String type, AuthCallback callback) {
AuthRequest authRequest = factory.get(type);
if (StringUtils.isNotEmpty(callback.getAuthorization_code())) {
log.info("----------------------------");
}
AuthResponse response = authRequest.login(callback);
TokenDTO result = getTokenDTO(response);
return result;
}
private static TokenDTO getTokenDTO(AuthResponse response) {
log.info("【response】= {}", JSON.toJSONString(response));
Object data = response.getData();
Map<String, Object> dataMap = JsonUtils.convertValue(data, new TypeReference<Map<String, Object>>() {
});
Object tokenData = dataMap.get(JWTConstant.TOKEN);
TokenDTO result = JsonUtils.convertValue(tokenData, new TypeReference<TokenDTO>() {
});
return result;
}
/**
* 刷新token
*
* @param type 第三方类型
* @param token 刷新token
* @return: {@link TokenDTO}
* @throws:
*/
@Override
public TokenDTO refresh(String type, AuthToken token) {
AuthRequest authRequest = factory.get(type);
AuthResponse response = authRequest.refresh(token);
log.info("【response】= {}", JSON.toJSONString(response));
Object data = response.getData();
TokenDTO result = JsonUtils.convertValue(data, new TypeReference<TokenDTO>() {
});
return result;
}
}
3.2.2.5 JWT内容含义
字段 | 含义 |
---|---|
name | 用户登录名 |
sub | 用户id |
tenant | 租户id |
client_id | 密钥key |
server | 是否服务 |
exp | 过期时间(时间戳) |
scope | 授权范围 |
flag | 用户类型(管理员=1,员工=2,客户=4) |
iat | 颁发时间 |