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 匿名令牌