将自定义UserDetailsService添加到Spring Security OAuth2应用程序
如何将下面的自定义将自定义UserDetailsService添加到Spring Security OAuth2应用程序,spring,spring-security,spring-boot,spring-security-oauth2,spring-oauth2,Spring,Spring Security,Spring Boot,Spring Security Oauth2,Spring Oauth2,如何将下面的自定义userdetails服务添加到 默认用户和默认密码在authserver应用程序的文件中定义 但是,出于测试目的,我想添加以下自定义UserDetailsService: package demo; import java.util.List; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.Author
userdetails服务添加到
默认用户
和默认密码
在authserver
应用程序的文件中定义
但是,出于测试目的,我想添加以下自定义UserDetailsService
:
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;
}
}
我尝试在OAuth2AuthorizationConfig
中使用@Autowire
将用户连接到授权服务器端点配置器
,如下所示:
@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引导日志表明没有找到用户Samwise
,这意味着UserDetailsService
没有成功连接。以下是Spring引导日志的相关摘录:
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
来验证刷新令牌,但我认为我的解决方案也会对您有所帮助
与您一样,我第一次尝试使用AuthorizationServerEndpointsConfigure
指定UserDetailsService
,但这不起作用。我不确定这是一个bug还是出于设计,但是需要在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);
}
当然,您还需要添加@autowiredusers-userDetailsService代码>Web安全配置适配器中的某个位置
我想提及的其他事项:
这可能是特定于版本的,我使用的是spring-security-oauth2.0.12
我无法举出任何来源来解释为什么会这样,我甚至不确定我的解决方案是真正的解决方案还是黑客
指南中提到的globalaauthenticationmanagerconfiguer
几乎可以肯定是一个打字错误,我在Spring的源代码中找不到该字符串李>
我遇到了相同的问题,最初的解决方案与Manan Mehta发布的相同。就在最近,spring security和spring oauth2的某些版本组合导致任何刷新令牌的尝试,导致HTTP 500错误,指出在我的日志中需要UserDetailsService
相关堆栈跟踪如下所示:
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
的对象,而不是我的userdetailssservice
。即使在我的websecurityConfigureAdapter
中设置了UserDetailsService
,还有两个websecurityConfigureAdapter
s。一个用于ResourceServerConfiguration
,另一个用于AuthorizationServerSecurityConfiguration
,这些配置从未获得我设置的UserDetailsService
在通过Spring Security一路追踪来拼凑正在发生的事情时,我发现有一个“本地”AuthenticationManagerBuilder
和一个“全局”AuthenticationManagerBuilder
,我们需要在全局版本上设置它,以便将此信息传递给这些其他构建器上下文
因此,我提出的解决方案是以与其他上下文获取全局版本相同的方式获取“全局”版本。在我的websecurityConfigureAdapter
中,我有以下内容:
@Autowired
public void setApplicationContext(ApplicationContext context) {
super.setApplicationContext(context);
AuthenticationManagerBuilder globalAuthBuilder = context
.getBean(AuthenticationManagerBuilder.class);
try {
globalAuthBuilder.userDetailsService(userDetailsService);
} catch (Exception e) {
e.printStackTrace();
}
}
这起作用了。其他上下文现在有myUserDetailsService
。我把这个留给将来偶然发现这个雷区的勇敢士兵。对于任何获得userdetails服务的人,在执行刷新令牌时需要服务错误,并且您确认您已经拥有userdetails服务
bean
尝试添加以下内容:
@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);
}
}
这是我的尝试和错误,可能不适合你
顺便说一句,如果您放弃“猜测”spring将选择哪个bean,您可以扩展AuthorizationServerConfigurerAdapter
和WebSecurityConfigureAdapter
并自行配置所有内容,但我认为这会失去spring自动配置的功能。
如果我只需要自定义一些配置,为什么我需要配置所有内容?我的要求是从oauth2电子邮件属性的后面获取一个数据库对象。我发现这个问题是因为我假设我需要创建一个自定义的用户详细信息服务。实际上,我需要实现OidcUser接口并将其挂接到该过程中
起初我认为它是OAuth2UserService,但我已经设置了AWS Cognito身份验证提供程序,以便它是开放的id connect
//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
}
//内部Web安全配置适配器
http
.oauth2Login()
.userInfoEndpoint()
.oidcUserService(新的CustomOidcUserServiceImpl());
...
公共类CustomOidcUserServiceImpl实现OAuth2UserService{
私有OidcUserService OIDCUSERVICE=新OIDCUSERVICE();
@凌驾
公共OidcUser loadUser(OidcUserRequest userRequest)引发OAuth2AuthenticationException{
OidcUser OidcUser=oidcUserService.loadUser(userRequest);
返回新的CustomUserPrincipal(oidcUser);
}
}
...
公共类CustomUserPrincipal实现了OidcUser{
私人用户;
//将所有呼叫转接到包含的呼叫器
}
定制服务是任何定制逻辑都可以使用的地方。
我计划在我的CustomUserPrincipal
上实现UserDetails
接口,这样我就可以为live和tes提供不同的身份验证机制
//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
}