【发布时间】:2017-08-03 23:21:00
【问题描述】:
在 Spring Boot 应用程序中,我有一个内存中的 Spring Security 设置。它可以按需要工作。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("kevin").password("password1").roles("USER").and()
.withUser("diana").password("password2").roles("USER", "ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/foos").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/foos/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/foos/**").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/foos/**").hasRole("ADMIN")
.and()
.csrf().disable();
}
}
现在,我使用以下代码将其转换为基于数据库的方法。
@Entity
class Account {
enum Role {ROLE_USER, ROLE_ADMIN}
@Id
@GeneratedValue
private Long id;
private String userName;
// @JsonIgnore
private String password;
@ElementCollection(fetch = FetchType.EAGER)
Set<Role> roles = new HashSet<>();
...
}
存储库:
@RepositoryRestResource
interface AccountRepository extends CrudRepository<Account, Long>{
@PreAuthorize("hasRole('USER')")
Optional<Account> findByUserName(@Param("userName") String userName);
}
UserDetailsService:
@Component
class MyUserDetailsService implements UserDetailsService {
private AccountRepository accountRepository;
MyUserDetailsService(AccountRepository accountRepository){
this.accountRepository = accountRepository;
}
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
Optional<Account> accountOptional = this.accountRepository.findByUserName(name);
if(!accountOptional.isPresent())
throw new UsernameNotFoundException(name);
Account account = accountOptional.get();
return new User(account.getUserName(), account.getPassword(),
AuthorityUtils.createAuthorityList(account.getRoles().stream().map(Account.Role::name).toArray(String[]::new)));
}
}
以及WebSecurityConfigurerAdapter配置的修改:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private MyUserDetailsService userDetailsService;
SecurityConfiguration(MyUserDetailsService userDetailsService){
this.userDetailsService = userDetailsService;
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService); // <-- replacing the in-memory anthentication setup
}
...
}
当我使用 一对用户名和密码作为基本身份验证发送相同的请求时,对于内存版本,我却收到 401 错误:
{
"timestamp": 1489430818803,
"status": 401,
"error": "Unauthorized",
"message": "An Authentication object was not found in the SecurityContext",
"path": "/foos"
}
在阅读了一些相关文档和示例代码后,我看不到错误的原因。错误消息说的是用户不在 Spring Security 上下文中。 userDetailsService(userDetailsService) 中的 AuthenticationManagerBuilder 使用行应该负责在 SecurityContext 中设置这些用户,不是吗?
Spring Boot 版本是 1.4.3.RELEASE。
【问题讨论】:
标签: spring-boot spring-security