将自定义UserDetailsService添加到Spring Security OAuth2应用程序



如何将下面的自定义UserDetailsService添加到此Spring OAuth2示例?

默认user和默认passwordauthserver应用程序的application.properties文件中定义。

但是,出于测试目的,我想将以下自定义UserDetailsService添加到authserver应用程序的demo包中:

package demo;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Service;
@Service
class Users implements UserDetailsManager {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        String password;
        List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
        if (username.equals("Samwise")) {
            auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT");
            password = "TheShire";
        }
        else if (username.equals("Frodo")){
            auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT");
            password = "MyRing";
        }
        else{throw new UsernameNotFoundException("Username was not found. ");}
        return new org.springframework.security.core.userdetails.User(username, password, auth);
    }
    @Override
    public void createUser(UserDetails user) {// TODO Auto-generated method stub
    }
    @Override
    public void updateUser(UserDetails user) {// TODO Auto-generated method stub
    }
    @Override
    public void deleteUser(String username) {// TODO Auto-generated method stub
    }
    @Override
    public void changePassword(String oldPassword, String newPassword) {
        // TODO Auto-generated method stub
    }
    @Override
    public boolean userExists(String username) {
        // TODO Auto-generated method stub
        return false;
    }
}

正如您所看到的,这个UserDetailsService还不是autowired,它故意使用不安全的密码,因为它只是为测试目的而设计的。

需要对GitHub示例应用程序进行哪些特定更改,以便用户可以使用password=TheShireusername=Samwise登录,或者使用password=MyRingusername=Frodo登录是否需要对AuthserverApplication.java或其他地方进行更改?


建议:


Spring OAuth2开发人员指南规定使用GlobalAuthenticationManagerConfigurer全局配置UserDetailsService。然而,在谷歌上搜索这些名字并不会产生什么有用的结果。

此外,另一个使用内部spring-security INSTEAD OF OAuth的应用程序使用以下语法来连接UserDetailsService,但我不确定如何将其语法调整为当前的OP:

@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
    @Autowired
    private Users users;
    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(users);
    }
}

我尝试在OAuth2AuthorizationConfig中使用@AutowireUsers连接到AuthorizationServerEndpointsConfigurer,如下所示:

@Autowired//THIS IS A TEST
private Users users;//THIS IS A TEST
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
   endpoints.authenticationManager(authenticationManager)
        .accessTokenConverter(jwtAccessTokenConverter())
        .userDetailsService(users)//DetailsService)//THIS LINE IS A TEST
        ;
}

但是Spring Boot日志表明没有找到用户Samwise,这意味着UserDetailsService没有成功连接。以下是Spring Boot日志的相关摘录:

2016-04-20 15:34:39.998 DEBUG 5535 --- [nio-9999-exec-9] o.s.s.a.dao.DaoAuthenticationProvider    :  
        User 'Samwise' not found
2016-04-20 15:34:39.998 DEBUG 5535 --- [nio-9999-exec-9]   
        w.a.UsernamePasswordAuthenticationFilter :  
        Authentication request failed:  
        org.springframework.security.authentication.BadCredentialsException:  
        Bad credentials

我还能尝试什么

我在使用Spring Security开发oauth服务器时遇到了类似的问题。我的情况略有不同,因为我想添加UserDetailsService来验证刷新令牌,但我认为我的解决方案也会对您有所帮助。

和您一样,我第一次尝试使用AuthorizationServerEndpointsConfigurer指定UserDetailsService,但这不起作用。我不确定这是一个错误还是设计错误,但需要在AuthenticationManager中设置UserDetailsService,以便各种oauth2类找到它

@Configuration
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired
  Users userDetailsService;
  @Autowired
  public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService);
  }
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
    // other stuff to configure your security
  }
}

我认为,如果你从第73行开始更改以下内容,它可能对你有用:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.parentAuthenticationManager(authenticationManager)
        .userDetailsService(userDetailsService);
}

当然,您还需要在WebSecurityConfigurerAdapter 中的某个位置添加@Autowired Users userDetailsService;

我想提到的其他事情:

  1. 这可能是特定于版本的,我使用的是spring-security-outh2 2.0.12
  2. 我无法引用任何来源来解释为什么会这样,我甚至不确定我的解决方案是真正的解决方案还是黑客
  3. 指南中提到的GlobalAuthenticationManagerConfigurer几乎可以肯定是一个拼写错误,我在Spring的源代码中找不到这个字符串

我的要求是从oauth2电子邮件属性的后面获取一个数据库对象。我发现了这个问题,因为我认为我需要创建一个自定义的用户详细信息服务。事实上,我需要实现OidcUser接口并连接到该过程中。

起初我以为它是OAuth2UserService,但我已经设置了我的AWS Cognito身份验证提供商,使其成为开放的id连接。。

//inside WebSecurityConfigurerAdapter
http
.oauth2Login()
.userInfoEndpoint()
.oidcUserService(new CustomOidcUserServiceImpl());
...
public class CustomOidcUserServiceImpl implements OAuth2UserService<OidcUserRequest, OidcUser> {
    private OidcUserService oidcUserService = new OidcUserService();
    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
        OidcUser oidcUser = oidcUserService.loadUser(userRequest);
        return new CustomUserPrincipal(oidcUser);
    }
}
...
public class CustomUserPrincipal implements OidcUser {
    private OidcUser oidcUser;
    //forward all calls onto the included oidcUser
}

定制服务是任何定制逻辑都可以使用的地方。我计划在我的CustomUserPrincipal上实现UserDetails接口,这样我就可以拥有不同的实时和测试身份验证机制,以便于自动化ui测试。

我遇到了同样的问题,最初的解决方案与Manan Mehta发布的相同。就在最近,spring-security和spring-oauth2的某些版本组合导致任何刷新令牌的尝试,导致HTTP500错误,在我的日志中声明UserDetailsService is required

相关堆栈跟踪如下所示:

java.lang.IllegalStateException: UserDetailsService is required.
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:463)
at org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper.loadUserDetails(UserDetailsByNameServiceWrapper.java:68)
at org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider.authenticate(PreAuthenticatedAuthenticationProvider.java:103)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
at org.springframework.security.oauth2.provider.token.DefaultTokenServices.refreshAccessToken(DefaultTokenServices.java:150)

您可以在底部看到DefaultTokenServices正在尝试刷新令牌。然后,它调用AuthenticationManager进行重新身份验证(以防用户撤销权限或用户被删除等),但这就是一切的症结所在。您可以在堆栈跟踪的顶部看到,UserDetailsServiceDelegator是对loadUserByUsername的调用,而不是我漂亮的UserDetailsService。尽管在我的WebSecurityConfigurerAdapter中,我设置了UserDetailsService,但还有另外两个WebSecurityConfigurerAdapter。一个用于ResourceServerConfiguration,一个用于AuthorizationServerSecurityConfiguration,这些配置永远不会得到我设置的UserDetailsService

在通过Spring Security进行跟踪以拼凑正在发生的事情时,我发现有一个"本地"AuthenticationManagerBuilder和一个"全局"AuthenticationManagerBuilder,我们需要在全局版本上设置它,以便将这些信息传递给其他构建器上下文。

因此,我提出的解决方案是以其他上下文获得全局版本的方式获得"全局"版本。在我的WebSecurityConfigurerAdapter中,我有以下内容:

@Autowired
public void setApplicationContext(ApplicationContext context) {
    super.setApplicationContext(context);
    AuthenticationManagerBuilder globalAuthBuilder = context
            .getBean(AuthenticationManagerBuilder.class);
    try {
        globalAuthBuilder.userDetailsService(userDetailsService);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

这起到了作用。其他上下文现在有我的UserDetailsService。我把这件事留给将来偶然发现这个雷区的任何勇敢的士兵。

对于任何在刷新令牌时出现UserDetailsService is required错误的人,您确认您已经有了UserDetailsServicebean。

试着添加这个:

@Configuration
public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter {
    private UserDetailsService userDetailsService;
    public GlobalSecurityConfig(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }
}

这是我的尝试和错误,也许对你不起作用。

顺便说一句,如果你放弃"猜测"哪个bean将在春天采摘,你可以扩展AuthorizationServerConfigurerAdapterWebSecurityConfigurerAdapter,并自己配置所有东西,但我认为这已经失去了春天自动配置的能力。如果我只需要自定义一些配置,为什么我需要配置所有内容?

相关内容

最新更新