OAuth2用户详细信息未在春季安全(SpringBoot)中更新

Posted

技术标签:

【中文标题】OAuth2用户详细信息未在春季安全(SpringBoot)中更新【英文标题】:OAuth2 userdetails not updating in spring security (SpringBoot) 【发布时间】:2017-10-29 01:27:22 【问题描述】:

我是 Spring Security 的新手,并且使用过 jhipster,我在其中配置了基于 db 和 LDAP 的身份验证。现在我使用@enableOAuthSso 将它与OAuth 客户端集成。我可以使用外部 OAuth Idp (Okta) 进行身份验证,它正在重定向到我的应用程序,我的原则正在更新,我可以通过休息访问资源。但是我的 userDetails 对象没有被填充。

@Inject
public void configureGlobal(AuthenticationManagerBuilder auth) 
    try 

        auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());

        auth
            .ldapAuthentication()
            .ldapAuthoritiesPopulator(ldapAuthoritiesPopulator)
            .userDnPatterns("uid=0,ou=people")
            .userDetailsContextMapper(ldapUserDetailsContextMapper)
            .contextSource(getLDAPContextSource());

     catch (Exception e) 
        throw new BeanInitializationException("Security configuration failed", e);
    

我已经深入检查失败的地方并发现了以下内容

public static String getCurrentUserLogin() 
    SecurityContext securityContext = SecurityContextHolder.getContext();
    Authentication authentication = securityContext.getAuthentication();
    String userName = null;
    if (authentication != null) 
        log.info("authentication is not null");
        if (authentication.getPrincipal() instanceof UserDetails)  //failing here
            log.info("principle is instance of userdetails");
            UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
            log.info(springSecurityUser.getUsername());
            userName = springSecurityUser.getUsername();
         else if (authentication.getPrincipal() instanceof String) 
            userName = (String) authentication.getPrincipal();
        
    
    return userName;

失败了

if(authentication.getPrincipal() instanceof UserDetails)

处理此更新用户详细信息对象的可能和最佳方法是什么。

更新:

@Transactional(readOnly = true)
public User getUserWithAuthorities() 
    log.info("======inside getUserWithAuthorities =================");
    log.info("current user is :::::::"+SecurityUtils.getCurrentUserLogin());
    Optional<User> optionalUser = userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin());
    User user = null;
    if (optionalUser.isPresent()) 
        user = optionalUser.get();
        user.getAuthorities().size(); // eagerly load the association
    
    return user;

它试图从数据库中获取用户。但用户不在数据库中

【问题讨论】:

【参考方案1】:

类似于the LDAP tip,我建议创建一个 OktaUserDetails 类并转换主体。然后您可以保持大部分身份验证代码相同。 LDAP 代码示例如下,OktaUserDetails 的格式将取决于 JSON 响应

 else if (authentication.getPrincipal() instanceof LdapUserDetails) 
    LdapUserDetails ldapUser = (LdapUserDetails) authentication.getPrincipal();
    return ldapUser.getUsername();

要保存从 Oauth2 资源接收到的信息,请在您的 SecurityConfiguration 中声明一个 PrincipalExtractor Bean。这使您可以以自定义方式解析响应。下面是一个基本示例 (source)。

@Bean
public PrincipalExtractor principalExtractor(UserRepository userRepository) 
    return map -> 
        String principalId = (String) map.get("id");
        User user = userRepository.findByPrincipalId(principalId);
        if (user == null) 
            LOGGER.info("No user found, generating profile for ", principalId);
            user = new User();
            user.setPrincipalId(principalId);
            user.setCreated(LocalDateTime.now());
            user.setEmail((String) map.get("email"));
            user.setFullName((String) map.get("name"));
            user.setPhoto((String) map.get("picture"));
            user.setLoginType(UserLoginType.GOOGLE);
            user.setLastLogin(LocalDateTime.now());
         else 
            user.setLastLogin(LocalDateTime.now());
        
        userRepository.save(user);
        return user;
    ;

【讨论】:

LDAP 工作正常,因为在身份验证成功后,我将用户复制到应用程序数据库。实际上问题在于基于 OAuth 的身份验证。在这种情况下,我正在从 okta 进行身份验证,但 userdetails 未更新,因此我的 ui 显示为我是匿名用户。我已经尝试过身份验证成功处理程序,但它没有调用。 对不起,我误解了你的问题。看起来您已经发现身份验证不为空,并且您知道它不是instanceof UserDetails。您是否尝试添加 else 子句并记录 authentication.getPrincipal() 包含的内容? 它给出了一个字符串,其中我的名字和姓氏之间附加了空格。你可以看到我为原则here 得到的实际 json。下一个失败的地方是 UserService.getUserWithAuthorities。 我想创建一个新的 OktaUser 并将主体转换为该用户以获取必要的信息并注入到 getUserWithAuthorities 中的 User 对象。这是最好的方法还是我应该尝试将用户复制到数据库,这在应用程序级别处理用户及其角色并没有更好的效果,我在 LDAP 中也是如此。我尝试使用身份验证成功处理程序,但它没有被触发。我不确定,我应该为此配置 SecurityConfig 文件吗?关于此的任何观点。 我会根据您想要的“真相来源”作为您的决定。如果您在登录时导入权限,然后他们在 Okta 上更改,用户可能在您的应用中拥有额外的权限(我没有使用 Okta,所以这可能不正确)。

以上是关于OAuth2用户详细信息未在春季安全(SpringBoot)中更新的主要内容,如果未能解决你的问题,请参考以下文章

Spring 安全客户端详细信息将作为 DaoAuthenticationProvider 中的用户详细信息

带有 OAuth2.0 的 Spring REST 不起作用

Spring Security OAuth2 JWT 匿名令牌

Spring Boot OAuth2:如何检索用户令牌信息详细信息

Spring安全和角度

Spring Security Oauth2:主体对象未返回扩展的用户详细信息