如何将下面的自定义UserDetailsService
添加到this Spring OAuth2 sample?
默认user
默认password
在authserver
应用的application.properties
文件中定义。
但是,我想将以下自定义UserDetailsService
添加到the demo
package of the authserver
app以进行测试:
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
,并且它故意使用不安全的密码,因为它仅用于测试目的。
需要对the GitHub sample app进行哪些具体更改,以便用户可以使用username=Samwise
作为password=TheShire
进行登录,或使用username=Frodo
作为password=MyRing
进行登录}?是否需要对AuthserverApplication.java
或其他地方进行更改?
建议:
Spring OAuth2 Developer Guide表示要使用GlobalAuthenticationManagerConfigurer
全局配置UserDetailsService
。但是,使用Google搜索这些名称会产生不太有用的结果。
此外,使用内部弹簧安全性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);
}
}
我尝试在@Autowire
内使用OAuth2AuthorizationConfig
将Users
连接到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
我还能尝试什么?
答案 0 :(得分:4)
在使用Spring Security开发我的oauth服务器时遇到了类似的问题。我的情况略有不同,因为我想添加UserDetailsService
来验证刷新令牌,但我认为我的解决方案也会对您有所帮助。
与您一样,我首先尝试使用UserDetailsService
指定AuthorizationServerEndpointsConfigurer
,但这不起作用。我不确定这是错误还是设计错误,但需要在UserDetailsService
中设置AuthenticationManager
,以便各种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);
}
您当然还需要在@Autowired Users userDetailsService;
WebSecurityConfigurerAdapter
我想提及的其他事项:
GlobalAuthenticationManagerConfigurer
几乎肯定是一个拼写错误,我无法在源代码中的任何位置找到该字符串以用于Spring中的任何内容。 答案 1 :(得分:2)
我遇到了同样的问题,最初的解决方案与Manan Mehta发布的解决方案相同。就在最近,spring安全和spring oauth2的某种版本组合导致任何尝试刷新令牌的尝试,导致HTTP 500错误,指出我的日志中的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
,我们需要将其设置为on全局版本,以便将此信息传递到其他构建器上下文。
因此,我想出的解决方案是以与其他上下文获取全局版本相同的方式获取“全局”版本。在我的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
。我把这留给将来遇到这个雷区的任何勇敢的士兵。
答案 2 :(得分:0)
对于任何人在执行刷新令牌时遇到UserDetailsService is required
错误,并且您确认您已经拥有UserDetailsService
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);
}
}
这是我的尝试,可能对您不起作用。
顺便说一句,如果您放弃了在春季之前将要选择的bean的“猜测”,则可以扩展AuthorizationServerConfigurerAdapter
和WebSecurityConfigurerAdapter
并自行配置所有内容,但是我认为它失去了spring的功能自动配置。
如果只需要自定义一些配置,为什么我需要配置所有内容?
答案 3 :(得分:0)
我的要求是从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
}
自定义服务是任何定制逻辑都可以使用的地方。
我计划在自己的UserDetails
上实现CustomUserPrincipal
接口,以便可以对实时和测试使用不同的身份验证机制,以促进自动化ui测试。