跳到主要内容

如何集成三方 Oauth2 单点登录

如何集成

  1. 配置文件追加自定义的 oauth2 类型

    1702397383489

  2. 添加自定义 oauth2 类型枚举

    1702397344304

  3. 添加自定义 oauth2 类型相关地址信息

    1702397398565

  4. 自定义 oauth2 实现,代码建参考

    1702397413210

  5. 注入实现

    1702397426822

  6. 前端登录页添加 oauth2 跳转图标

    1702397436278

常见问题

  1. 如何直接通过 oauth2 url 进入到系统而不通过登录页面点击?

可以直接通过如下地址,记得在配置文件里面配置 ignore-check-state=true,忽略 state 的校验,http://ip:port/oauth/authorize?response_type=code&client_id=xxxxx&state=300ec11cb0cef12c23b8ba137fe7f51e&scope=all&redirect_uri=https://surveykingpro.cn/user/login

参考代码

package cn.surveyking.framework.social.core.custom;

import cn.hutool.core.codec.Base64;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.surveyking.framework.social.core.enums.AuthExtendSource;
import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthDefaultRequest;
import me.zhyd.oauth.utils.UrlBuilder;

import java.util.LinkedHashMap;
import java.util.Map;

/**
* @author javahuang
* @date 2023/11/13
*/
public class AuthCustomRequest extends AuthDefaultRequest {


public AuthCustomRequest(AuthConfig config) {
super(config, AuthExtendSource.CUSTOM_SOURCE);
}

public AuthCustomRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthExtendSource.CUSTOM_SOURCE, authStateCache);
}

@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
String tokenUrl = accessTokenUrl(authCallback.getCode());
Map<String, Object> paramMap = new LinkedHashMap<>();
String encode = Base64.encode(String.format("%s:%s", config.getClientId(), config.getClientSecret()));
paramMap.put("code", authCallback.getCode());
paramMap.put("client_id", config.getClientId());
paramMap.put("grant_type", "authorization_code");
paramMap.put("redirect_uri", config.getRedirectUri());
paramMap.put("scope", "all");
String response = HttpRequest.post(tokenUrl).header("Content-Type", "application/x-www-form-urlencoded")
.header(Header.AUTHORIZATION, String.format("Basic %s", encode))// 头信息,多个头信息多次调用此方法即可
.form(paramMap)// 表单内容
.timeout(20000)// 超时,毫秒
.execute().body();

JSONObject object = JSONObject.parseObject(response);
return AuthToken.builder().accessToken(object.getString("access_token"))
.refreshToken(object.getString("refresh_token")).idToken(object.getString("id_token"))
.tokenType(object.getString("token_type")).scope(object.getString("scope")).build();

}

@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String response = doGetUserInfo(authToken);
JSONObject object = JSONObject.parseObject(response);

this.checkResponse(object);

return AuthUser.builder()
.uuid(object.getString("id"))
.username(object.getString("username"))
.nickname(object.getString("name"))
.avatar(object.getString("avatar_url"))
.blog(object.getString("web_url"))
.company(object.getString("organization"))
.location(object.getString("location"))
.email(object.getString("email"))
.remark(object.getString("bio"))
.gender(AuthUserGender.UNKNOWN)
.token(authToken)
.source(source.toString())
.build();
}

private void checkResponse(JSONObject object) {
// oauth/token 验证异常
if (object.containsKey("error")) {
throw new AuthException(object.getString("error_description"));
}
// user 验证异常
if (object.containsKey("message")) {
throw new AuthException(object.getString("message"));
}
}

/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.11.0
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(super.authorize(state)).queryParam("scope", "all").build();

}
}