带有 Spring Security 的 Spring REST 不接受凭据
Posted
技术标签:
【中文标题】带有 Spring Security 的 Spring REST 不接受凭据【英文标题】:Spring REST with Spring Security not accepting credentials 【发布时间】:2019-01-05 02:56:35 【问题描述】:我正在使用 Spring REST 创建一个 REST API,并尝试使用 Spring Security 对其进行保护以进行基本身份验证。它由 MariaDB 数据库提供支持。
我用过this guide for setting up basic authentication。我已经到了可以发出 POST 请求以在数据库中创建新用户凭据的位置,但是当我转身尝试使用这些凭据访问受保护的端点时,我得到了 401 Unauthorized 响应。
谁能指出我哪里出错了?谢谢!
这是我的实体:
@Entity
@Table(name="credentials")
public class Credential
public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
@Id
@GenericGenerator(name = "uuid", strategy = "uuid2")
@GeneratedValue(generator="uuid")
@Column(name="user_id")
private UUID userId;
@Column(name="username")
private String username;
@Column(name="password")
private String password;
@Column(name="updated_at")
private LocalDateTime updatedAt;
@Column(name="created_at")
private LocalDateTime createdAt;
@OneToOne(fetch=FetchType.EAGER)
@JoinColumn(name="user_id")
private User user;
public Credential(UUID userId, String username, String password, LocalDateTime updatedAt, LocalDateTime createdAt)
this.userId = userId;
this.username = username;
setPassword(password);
this.updatedAt = updatedAt;
this.createdAt = createdAt;
public Credential()
...and standard getters and setters
这是我的存储库:
public interface CredentialRepository extends CrudRepository<Credential, UUID>
Optional<Credential> findByUsername(String username);
我的类扩展了 UserDetailsService:
@Component
public class DetailsService implements UserDetailsService
@Autowired
private CredentialRepository credentials;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
Optional<Credential> credential = credentials.findByUsername(username);
if (!credential.isPresent())
throw new UsernameNotFoundException(username + " not found");
return new User(credential.get().getUsername(), credential.get().getPassword(),
AuthorityUtils.createAuthorityList("ROLE_USER"));
@Transactional
public Credential signupNewAccount(Credential credential) throws DuplicateUsernameException
if(usernameExists(credential.getUsername()))
throw new DuplicateUsernameException("That username is not available: " + credential.getUsername());
Credential registered = new Credential();
registered.setUsername(credential.getUsername());
registered.setPassword(credential.getPassword());
return credentials.save(registered);
private boolean usernameExists(String username)
Optional<Credential> candidate = credentials.findByUsername(username);
if(candidate.isPresent())
return true;
else
return false;
还有我的 WebSecurityConfigurerAdapter:
@Component
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter
@Autowired
private DetailsService detailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(detailsService).passwordEncoder(Credential.PASSWORD_ENCODER);
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/v1/login").permitAll()
.antMatchers(HttpMethod.POST, "/v1/signup").permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().sessionManagement().disable();
我发送到另一个端点的 HTTP GET 请求:
GET /v1/boards HTTP/1.1
Host: localhost:8443
Authorization: Basic dGVzdDp0ZXN0
Cache-Control: no-cache
以及来自服务器的响应:
HTTP/1.1 401
WWW-Authenticate: Basic realm="Realm"
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=0FE1E2736168B8C24980059A2546CA95; Path=/; Secure; HttpOnly
WWW-Authenticate: Basic realm="Realm"
Content-Length: 0
Date: Sat, 28 Jul 2018 20:36:37 GMT
【问题讨论】:
【参考方案1】:花了一天时间阅读了每篇关于 Spring Security 和 Basic Authentication 的文章后,我发现了问题所在。结果当我在数据库中注册凭据时,我对它们进行了两次加密。在我的 UserDetailsService 实现中更改注册方法修复了它:
@Transactional
public Credential signupNewAccount(Credential credential) throws DuplicateUsernameException
System.out.println("Enter signupNewAccount: " + credential.getUsername() + " / " + credential.getPassword());
if(usernameExists(credential.getUsername()))
throw new DuplicateUsernameException("That username is not available: " + credential.getUsername());
return credentials.save(credential);
【讨论】:
以上是关于带有 Spring Security 的 Spring REST 不接受凭据的主要内容,如果未能解决你的问题,请参考以下文章
Understand Spring Security Architecture and implement Spring Boot Security
Apache Shiro 与 Spring Security