配置Spring Boot安全,允许路径)未授权401
Configuring Springboot security, permitted path(s) not authorised 401
我有一个 Springboot REST API,它有端点
/api/quizzes
GET
/api/quizzes/{id}
POST
/api/register
POST
/
GET
这是一个由 Thymeleaf 控制器管理的欢迎页面 class
我已按如下方式设置我的安全 class;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
/* This sets up the security on specified paths according to role of client */
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic()
.and().authorizeRequests()
.antMatchers("/api/quizzes/**").hasRole("USER")
// .antMatchers("/api/register/").permitAll() // have tried this, still 401
.antMatchers("/**").permitAll() // does not permit `/api/register` but does `/` and `h2-
// console
.and().headers().frameOptions().disable();
}
/* This sets up the user roles by searching the database for a match, so they can access the
endpoints configured above */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
现在,当我尝试在 Postman 中访问 /api/register
时,响应是 401 unauthorised
。我可以访问 /
。我知道 /**
是这个目录和任何子目录的通配符,所以它应该匹配 root 和 /api/register
,以及 permitAll()
?
编辑:更多信息
- 注释掉
SecurityConfig
中的所有代码,我可以访问 /
、/api/quizzes
、/api/quizzes/{id}
但不能访问 /api/register
,事实上它 returns 403 而不是 401 这很有趣。
antMatchers("/**").permitAll()
,访问除 /api/register
之外的所有内容,现在响应是 401 ?
antMatchers("/**).authenticated()
, 一切 returns 401 未经授权
我想知道,所有 /api/quizzes
端点都在 QuizController
下,但是 /api/register
端点在它自己的 @RestController
控制器 class 下。我错过了注释吗?看不到,设置一样。
我知道 Spring 没有查看我的 UserService,因为没有打印 sout
消息。昨天我确实在某个时候使用了它,它正在从数据库 table 中获取 User
。我不确定发生了什么变化。
这是我的用户服务
@Service
public class UserService implements UserDetailsService {
@Autowired
static UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String email) {
Optional<User> user = userRepository.findByEmail(email);
System.out.println("loadByUsername called");
if (user.isPresent()) {
System.out.println("loadUserByUsername called: user.isPresent() = true");
return new MyUserDetails(user.get().getEmail(), user.get().getPassword());
} else {
throw new UsernameNotFoundException("User: " + email + " not found");
}
}
public static void saveUserToDB(User user) {
if (user.getPassword().length() < 5) {
throw new UsernameNotFoundException("password too short.");
}
Pattern pattern = Pattern.compile("simon\.aust@hotmail\.com");
Matcher matcher = pattern.matcher(user.getEmail());
if (!matcher.matches()) {
throw new UsernameNotFoundException("email not correct format");
}
userRepository.save(user);
}
}
用户存储库
public interface UserRepository extends CrudRepository<User, Long> {
Optional<User> findByEmail(String email);
}
我的用户详细信息
public class MyUserDetails implements UserDetails {
private final String username;
private final String password;
public MyUserDetails(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
编辑2;
通过内存中身份验证,我可以使用某些端点进行身份验证,但同样不能 /api/register
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.inMemoryAuthentication()
.passwordEncoder(org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
.withUser("user1")
.password("password")
.roles("USER");
}
试试这个:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/register/**").permitAll()
.antMatchers("/api/quizzes/**").authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
这是我费了好大劲才改过来的错误。
由于我的天真和忽略了我处理异常的位置,我实际上是在某些 if/else 语句上返回带有自定义异常的 HTTP 状态。这让我误以为用户身份验证不起作用,而事实上它是有效的。
今日课程:使用断点和调试 :)
我有一个 Springboot REST API,它有端点
/api/quizzes
GET
/api/quizzes/{id}
POST
/api/register
POST
/
GET
这是一个由 Thymeleaf 控制器管理的欢迎页面 class
我已按如下方式设置我的安全 class;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
/* This sets up the security on specified paths according to role of client */
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic()
.and().authorizeRequests()
.antMatchers("/api/quizzes/**").hasRole("USER")
// .antMatchers("/api/register/").permitAll() // have tried this, still 401
.antMatchers("/**").permitAll() // does not permit `/api/register` but does `/` and `h2-
// console
.and().headers().frameOptions().disable();
}
/* This sets up the user roles by searching the database for a match, so they can access the
endpoints configured above */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
现在,当我尝试在 Postman 中访问 /api/register
时,响应是 401 unauthorised
。我可以访问 /
。我知道 /**
是这个目录和任何子目录的通配符,所以它应该匹配 root 和 /api/register
,以及 permitAll()
?
编辑:更多信息
- 注释掉
SecurityConfig
中的所有代码,我可以访问/
、/api/quizzes
、/api/quizzes/{id}
但不能访问/api/register
,事实上它 returns 403 而不是 401 这很有趣。 antMatchers("/**").permitAll()
,访问除/api/register
之外的所有内容,现在响应是 401 ?antMatchers("/**).authenticated()
, 一切 returns 401 未经授权
我想知道,所有 /api/quizzes
端点都在 QuizController
下,但是 /api/register
端点在它自己的 @RestController
控制器 class 下。我错过了注释吗?看不到,设置一样。
我知道 Spring 没有查看我的 UserService,因为没有打印 sout
消息。昨天我确实在某个时候使用了它,它正在从数据库 table 中获取 User
。我不确定发生了什么变化。
这是我的用户服务
@Service
public class UserService implements UserDetailsService {
@Autowired
static UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String email) {
Optional<User> user = userRepository.findByEmail(email);
System.out.println("loadByUsername called");
if (user.isPresent()) {
System.out.println("loadUserByUsername called: user.isPresent() = true");
return new MyUserDetails(user.get().getEmail(), user.get().getPassword());
} else {
throw new UsernameNotFoundException("User: " + email + " not found");
}
}
public static void saveUserToDB(User user) {
if (user.getPassword().length() < 5) {
throw new UsernameNotFoundException("password too short.");
}
Pattern pattern = Pattern.compile("simon\.aust@hotmail\.com");
Matcher matcher = pattern.matcher(user.getEmail());
if (!matcher.matches()) {
throw new UsernameNotFoundException("email not correct format");
}
userRepository.save(user);
}
}
用户存储库
public interface UserRepository extends CrudRepository<User, Long> {
Optional<User> findByEmail(String email);
}
我的用户详细信息
public class MyUserDetails implements UserDetails {
private final String username;
private final String password;
public MyUserDetails(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
编辑2;
通过内存中身份验证,我可以使用某些端点进行身份验证,但同样不能 /api/register
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.inMemoryAuthentication()
.passwordEncoder(org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
.withUser("user1")
.password("password")
.roles("USER");
}
试试这个:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/register/**").permitAll()
.antMatchers("/api/quizzes/**").authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
这是我费了好大劲才改过来的错误。 由于我的天真和忽略了我处理异常的位置,我实际上是在某些 if/else 语句上返回带有自定义异常的 HTTP 状态。这让我误以为用户身份验证不起作用,而事实上它是有效的。 今日课程:使用断点和调试 :)