Cod*_*Med 7 spring spring-security spring-boot spring-security-oauth2 spring-oauth2
如何添加自定义UserDetailsService
下面这个春天的OAuth2样?
默认默认user
值在应用程序password
的application.properties
文件中定义authserver
.
不过,我想以下自定义添加UserDetailsService
到该demo
包中的authserver
应用程序用于测试目的:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,这UserDetailsService
还没有autowired
,它故意使用不安全的密码,因为它仅用于测试目的.
需要什么样的具体变化来进行GitHub的示例应用程序,使用户可以为登录username=Samwise
用password=TheShire
,或username=Frodo
用password=MyRing
? 是否需要对AuthserverApplication.java
其他地方进行更改?
几点建议:
在春天的OAuth2开发指南说,使用一个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);
}
}
Run Code Online (Sandbox Code Playgroud)
我试着用@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
;
}
Run Code Online (Sandbox Code Playgroud)
但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
Run Code Online (Sandbox Code Playgroud)
我还能尝试什么?
我的要求是从 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
}
Run Code Online (Sandbox Code Playgroud)
自定义服务是任何定制逻辑都可以使用的地方。我计划UserDetails
在我的上实现接口CustomUserPrincipal
,以便我可以为实时和测试提供不同的身份验证机制,以促进自动化 ui 测试。
小智 6
在使用 Spring Security 开发 oauth 服务器时,我遇到了类似的问题。我的情况略有不同,因为我想添加一个UserDetailsService
来验证刷新令牌,但我认为我的解决方案也会对您有所帮助。
像您一样,我首先尝试指定UserDetailsService
using 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
}
}
Run Code Online (Sandbox Code Playgroud)
我认为如果您从第 73 行开始更改以下内容,它可能对您有用:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
Run Code Online (Sandbox Code Playgroud)
您当然还需要在@Autowired Users userDetailsService;
某处添加WebSecurityConfigurerAdapter
我想提的其他事情:
GlobalAuthenticationManagerConfigurer
提到在引导几乎可以肯定是一个错字,我无法找到源代码串的任何地方对任何春。我遇到了同样的问题,最初与 Manan Mehta 发布的解决方案相同。就在最近,spring security 和 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)
Run Code Online (Sandbox Code Playgroud)
您可以在底部看到DefaultTokenServices
正在尝试刷新令牌。然后它调用一个AuthenticationManager
重新进行身份验证(以防用户撤销权限或用户被删除等),但这就是一切都无法解决的地方。你看到的堆栈跟踪的顶部UserDetailsServiceDelegator
是什么得到调用loadUserByUsername
,而不是我的美丽UserDetailsService
。即使在我的内部WebSecurityConfigurerAdapter
设置了UserDetailsService
,还有另外两个WebSecurityConfigurerAdapter
s。一个用于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();
}
}
Run Code Online (Sandbox Code Playgroud)
这奏效了。其他上下文现在有我的UserDetailsService
. 我把它留在这里,留给将来偶然发现这个雷区的任何勇敢的士兵。
归档时间: |
|
查看次数: |
11156 次 |
最近记录: |