文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

分析xxljob登入功能集成OIDC的统一认证

2024-04-02 19:55

关注

前言

xxl-job 是一款 java 开发的、开源的分布式任务调度系统,自带了登录认证功能,不支持对接、扩展 LDAP 、OIDC 等标准认证系统,考虑到单独维护 xxl-job 自有的用户系统不方便,以及存在人员离职、调岗、权限变动等需要及时调整用户权限的情况,需要接入公司统一的 OIDC 认证系统

相关链接

XXL-JOB 自身认证功能分析

xxl-job 自带的登录认证用户信息维护在 mysql 的 user 表中,用户从登录页提交用户名和密码,后端查询用户信息、校验密码,验证成功后设置登录信息到 cookie 中,采用 cookie 保持登录状态,大致的流程如下:

OIDC 的认证流程

OIDC(OpenID Connect) 是一种融合了 OpenID 、Oauth2 的身份认证协议。认证流程上和 Oauth2 基本一致,但是,OIDC 在 Oauth2 的 access\_token 基础上新增了一个使用 jwt 生成的 idToken,idToken 中携带了用户基本信息,使用私钥验签成功后,可直接使用,省略了通过 access\_token 获取用户信息的步骤。所以 OIDC 的认证流程既和 Oauth2 类似又有区别,基本流程如下:

这里注意最后第 6、7 点操作,这里开始 OIDC 和 Oauth2 不一样了

XXL-JOB 集成 OIDC 后的认证流程

从 OIDC 的认证流程得知,终端用户通过授权服务器授权认证后,授权服务器会携带 code 重定向到客户端服务,客户端通过 code 可以拿到用户唯一标识,通过这个唯一标识,可以继续完成客户端原本的认证流程。集成 OIDC 后,xxl-job 登录的大致流程如下:

集成 OIDC 后,系统认证保持用户登录状态的机制没有变化,依然使用  Cookie ,需要特殊处理以及关注地方有:

XXL-JOB 登录模块重新设计

考虑开发环境使用 OIDC 服务不方便以及解耦对第三方认证授权服务的依赖,决定在集成 OIDC 时,兼容本地登录功能,登录流程由登录模式来控制区分,登录模式使用配置驱动,设计集成 OIDC 后 ,xxl-job 支持的登录模式如下:

onlyLocal 模式登录界面:

mix 模式登录界面:

olnyOidc 模式登录界面:

olnyOidc 模式特殊,从设计上来说,如果需要保留用户使用习惯,可以保留一个跳转到 OIDC 授权服务器的链接按钮给用户点击。如果做的干净利落,在 olnyOidc 模式下,访问登录页可以直接 302 到 OIDC 授权服务器。

保留登录按钮的界面(实际这个页面取消了)

编码环节

配置属性类,省略了get、set


@ConfigurationProperties(prefix = "oidc")
@Configuration
public class OidcProperties {
    private static final LoginMod DEFAULT_LOGIN_MOD = LoginMod.onlyLocal;
    private LoginMod loginMod = DEFAULT_LOGIN_MOD;
    private String clientId;
    private String clientSecret;
    private String accessTokenUrl;
    private String profileUrl;
    private String redirectUri;
    private String logoutUrl;
    private String loginUrl;
    private ListadminLists = new ArrayList<>();
    public enum LoginMod {
        mix,
        onlyOidc,
        onlyLocal
    }
}

对应了如下的配置, 除了 login-mod  、redirect-uri 、admin-Lists 是 xxl-job 自身登录功能需要,其他的配置均由 OIDC 授权服务器提供

oidc.login-mod=onlyOidc
oidc.client-id = xxl-job-dev
oidc.client-secret = xx
oidc.base-url = https://sso.security.oidc.com oidc.access-token-url = ${oidc.base-url}/cas/oidc/accessToken
oidc.login-url = ${oidc.base-url}/cas/oidc/authorize?response_type=code&client_id=${oidc.client-id}&redirect_uri=${oidc.redirect-uri}&scope=openid
oidc.redirect-uri = http://172.26.203.103:8071/oidc/tokenLogin oidc.logout-url =${oidc.base-url}/cas/logout?service=${oidc.redirect-uri}
oidc.admin-Lists = chenkailing

Oidc 服务类,使用这个类里的方法和 OIDC 授权服务器交互


@Service
public class OidcService {
    private final OidcProperties oidcProperties;
    private final RestTemplate restTemplate;
    public OidcService(OidcProperties oidcProperties, RestTemplate restTemplate) {
        this.oidcProperties = oidcProperties;
        this.restTemplate = restTemplate;
    }
    
    public String getUsernameByCode(String code) {
        URI uri = UriComponentsBuilder.fromUriString(oidcProperties.getAccessTokenUrl())
                .queryParam("client_id", oidcProperties.getClientId())
                .queryParam("client_secret", oidcProperties.getClientSecret())
                .queryParam("redirect_uri", oidcProperties.getRedirectUri())
                .queryParam("code", code)
                .queryParam("grant_type", "authorization_code")
                .build()
                .toUri();
        AuthorizationEntity auth = restTemplate.getForObject(uri, AuthorizationEntity.class);
        Assert.notNull(auth, "AccessToken is null");
        String idToken = auth.getIdToken();
        int i = idToken.lastIndexOf('.');
        String withoutSignatureToken = idToken.substring(0, i+1);
        return Jwts.parserBuilder()
                .build()
                .parseClaimsJwt(withoutSignatureToken)
                .getBody()
                .get("sub", String.class);
    }
    
    public int getUserRole(XxlJobUser user) {
        ListadminLists = oidcProperties.getAdminLists();
        if (adminLists.contains(user.getUsername())) {
            return 1;
        }
        return 0;
    }
    public String getOidcLoginUrl() {
        return oidcProperties.getLoginUrl();
    }
    public OidcProperties.LoginMod getLoginMod() {
        return oidcProperties.getLoginMod();
    }
    public boolean isRedirectOidcLoginUrl() {
        return oidcProperties.getLoginMod().equals(OidcProperties.LoginMod.onlyOidc);
    }
    public String getLogoutUrl() {
        return oidcProperties.getLogoutUrl();
    }
    static class AuthorizationEntity {
        @JsonProperty("access_token")
        private String accessToken;
        @JsonProperty("id_token")
        private String idToken;
        @JsonProperty("refresh_token")
        private String refreshToken;
        @JsonProperty("expires_in")
        private String expiresIn;
        @JsonProperty("token_type")
        private String tokenType;
        private String scope;
    }
}

OIDC 登录接口,也就是提供给 OIDC 授权服务器回调的接口


@RequestMapping(value = "/oidc/tokenLogin", method = {RequestMethod.POST, RequestMethod.GET})
@PermissionLimit(limit = false)
public ModelAndView loginByOidc(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {
    if (loginService.ifLogin(request, response) != null) {
        modelAndView.setView(new RedirectView("/", true, false));
        return modelAndView;
    }
    String code = request.getParameter("code");
    if (Objects.isNull(code)) {
        return this.loginPageView();
    }
    String username = oidcService.getUsernameByCode(code);
    loginService.oidcLogin(username, response);
    modelAndView.setView(new RedirectView("/", true, false));
    return modelAndView;
}

这个接口对应了 xxl-job 集成 OIDC 后的认证流程:

跳转登录页逻辑做了封装,因为,根据登录模式的不同,有不同的处理逻辑:

private ModelAndView loginPageView() {
    ModelAndView modelAndView = new ModelAndView(LOGIN_PAGE);
    if (oidcService.isRedirectOidcLoginUrl()) {
        modelAndView.setView(new RedirectView(oidcService.getOidcLoginUrl(), true, false));
    } else {
        modelAndView.addObject("loginMod", oidcService.getLoginMod().name());
        modelAndView.addObject("oidcLoginUrl", oidcService.getOidcLoginUrl());
    }
    return modelAndView;
}

目前的策略,如果配置了登录模式为 onlyOidc ,则跳转登录页时,直接 302 到 OIDC 授权页,否则,将登录模式,和 OIDC 授权页传递给前端,由前端控制展示的 UI

以上就是分析xxljob登入功能集成OIDC的统一认证的详细内容,更多关于xxljob登入集成OIDC统一认证的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯