什么是通过类型安全方式访问通过春季安全的自定义OIDC属性(索赔)的最佳方法

发布于 2025-02-06 03:49:05 字数 3011 浏览 1 评论 0 原文

我们有一个使用OpenID Connect / Spring Security 5的Web应用程序来验证用户。 与我们在我们的spring Security中的开箱即用的OIDC支持非常简单。

使用OAuth2身份验证支持( oauth2login ) ,Identity提供商通过UserInfo端点公开了一些属性, 业务逻辑(最好以类型安全的方式)。这些属性在某些情况下是富有的对象的列表,使用通用 map&lt< string,object>

该userInfo端点的属性与default doken的属性合并到默认值<<<代码> oidcuserService ,然后放在 defaultoidCuser (以便它成为 oauth2authenticationToken )的

  • 一部分包含所有这些属性的DefaultoidCuser(使用映射)
  • java.security.principal = oauth2authenticationToken (又包含委托人,是我们的 default> defaultoidcuser
  • securitycontextholder.getContext()。getAuthentication() =再次相同 oauth2authenticationToken

因此要访问自定义属性,我可以

  1. 施放principal(or SecurityContexTholder.getContext() ))
public void doSomething(Principal principal) {
   OAuth2AuthenticationToken oAuth2AuthenticationToken = (OAuth2AuthenticationToken)principal;
   Map<String, Object> attributes = oAuth2AuthenticationToken.getPrincipal().getAttributes();
  ...
}

缺点是我需要施放,并且需要将地图转换为代码中的POJO“某个地方”,最好只有一次。

  1. 注入 @Authentication Principal defaultoidCuser 避免施放和访问属性。
public void doSomething(@AuthenticationPrincipal DefaultOidcUser defaultOidcUser) {
    Map<String, Object> attributes = defaultOidcUser.getAttributes();
    ...

}

在这里,我不需要施放,但仍然没有属性作为pojo。

以类型安全的方式轻松访问这些属性的最佳方法是什么?

提到 oauth2userservice ,我们有一个可以返回可以是自定义对象的 oidcuser 的钩子,以类型的安全方式公开我们的属性。

导致我进入选项nr 3

  1. 创建一个自定义 oidcuserService

    private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
        final OidcUserService delegate = new OidcUserService();

        return (userRequest) -> {
            // Load original user
            OidcUser oidcUser = delegate.loadUser(userRequest);

            // Parse custom claims
            CustomTypedAttributes customTypedAttributes = objectMapper.convertValue(oidcUser.getClaims(), CustomTypedAttributes.class);

            // Expose them as new custom user
            return new CustomOidcUser(oidcUser.getAuthorities(), oidcUser.getIdToken(), oidcUser.getUserInfo(), customTypedAttributes);
        };
    }

优势是我们通过 code> coductoidcuser.getCustomTypedAttributes(),对我们的自定义属性具有类型的安全访问一次(登录后)。

但是,将 oidcuser 像这样的 odcuser 揭露类型的安全属性映射并不感到“正确”。

是否有其他方法可以处理应用程序代码中的自定义属性:

  • 以一种安全的方式访问自定义属性。
  • 使用标准弹簧安全构建块
  • 测试友好的标准弹簧安全构建块(使用Spring Security Testing),

We have a web application using OpenID Connect / Spring Security 5 to authenticate users.
Integration is really simple with the out-of-the-box OIDC support in Spring Security using the oauth2 authentication support (oauth2Login)

The Identity Provider exposes some attributes via the userInfo endpoint that we need a lot in our business logic (preferably in a type-safe way). These attributes are in some cases lists of rich objects, something difficult to access using a generic Map<String,Object>

The attributes from that userInfo endpoint are merged with the attributes from the id token in the default OidcUserService, and put on the DefaultOidcUser (so that it becomes part of the OAuth2AuthenticationToken)

  • @AuthenticationPrincipal DefaultOidcUser defaultOidcUser = a DefaultOidcUser that contains all of these attributes (using Maps)
  • java.security.Principal = OAuth2AuthenticationToken (that in turn contains a principal, being our DefaultOidcUser)
  • SecurityContextHolder.getContext().getAuthentication() = again the same OAuth2AuthenticationToken

So to access the custom attributes I can

  1. cast the Principal (or SecurityContextHolder.getContext().getAuthentication())
public void doSomething(Principal principal) {
   OAuth2AuthenticationToken oAuth2AuthenticationToken = (OAuth2AuthenticationToken)principal;
   Map<String, Object> attributes = oAuth2AuthenticationToken.getPrincipal().getAttributes();
  ...
}

Downside here is I need to cast, and would need to convert the Map into a Pojo "somewhere" in the code, preferably only once.

  1. Inject a @AuthenticationPrincipal DefaultOidcUser to avoid casting and access the attributes.
public void doSomething(@AuthenticationPrincipal DefaultOidcUser defaultOidcUser) {
    Map<String, Object> attributes = defaultOidcUser.getAttributes();
    ...

}

Here I don't need to cast, but still don't have the attributes as a pojo.

What would be the best way to have easy access to these attributes in a type-safe way ?

The documentation mentions the OAuth2UserService, where we have a hook to return a OidcUser that could be a custom object, exposing our attributes in a type safe way.

Leading me to option nr 3

  1. Create a custom oidcUserService

    private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
        final OidcUserService delegate = new OidcUserService();

        return (userRequest) -> {
            // Load original user
            OidcUser oidcUser = delegate.loadUser(userRequest);

            // Parse custom claims
            CustomTypedAttributes customTypedAttributes = objectMapper.convertValue(oidcUser.getClaims(), CustomTypedAttributes.class);

            // Expose them as new custom user
            return new CustomOidcUser(oidcUser.getAuthorities(), oidcUser.getIdToken(), oidcUser.getUserInfo(), customTypedAttributes);
        };
    }

Advantage is we have type-safe access to our custom attributes, via customOidcUser.getCustomTypedAttributes(), they only need to be converted once (after login).

However, it doesn't feel "right" to wrap an OidcUser like this, just to expose a type safe attribute map.

Are there alternative ways of dealing with custom attributes in application code where the requirements are :

  • Easy access to custom attributes in a type safe way
  • Making use of the standard Spring Security building blocks
  • Test-friendly (using spring security testing)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文