Я работаю с приложением Spring. Все хорошо в браузере. Я могу войти с существующими пользователями, мне нужно указать только мое имя пользователя и пароль. Я также могу зарегистрироваться с новым пользователем, а затем войти в систему с ним.
У меня также есть некоторые конечные точки REST, которые я могу вызвать. Я не определял эти конечные точки вручную. Они были созданы автоматически, потому что я использую зависимость spring-boot-starter-data-rest.
URL-адрес запроса REST будет выглядеть примерно так: http://localhost:8182/api/v1/recipes.
Я пытаюсь получить список рецептов, используя Почтальон. Я хотел бы получить сообщение об ошибке, например «403 Forbidden», или что-то подобное, потому что я не предоставил никаких учетных данных. Вместо этого я получаю HTML-код страницы входа и код состояния «200 OK».
Это применимо также после того, как я предоставил имя пользователя и пароль в качестве заголовков запроса (возможно, мне нужно использовать другой способ предоставления учетных данных)
user:user
password:password
Следующий список содержит несколько фрагментов кода, чтобы показать все, что я написал в проекте, касающееся бита безопасности приложения:
Первый фрагмент кода представляет класс SecurityConfig из моего проекта:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private UserService userService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userService).passwordEncoder(User.PASSWORD_ENCODER);
}
@Override
public void configure(WebSecurity web) throws Exception{
web.ignoring().antMatchers("/css/**");
web.ignoring().antMatchers("/images/**");
web.ignoring().antMatchers("/js/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers("/sign-up").permitAll()
.anyRequest()
.hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.successHandler(loginSuccessHandler())
.failureHandler(loginFailureHandler())
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/login")
.and()
.csrf().disable();
}
public AuthenticationSuccessHandler loginSuccessHandler(){
return (request, response, authentication) ->{
response.sendRedirect("/recipes/");
};
}
public AuthenticationFailureHandler loginFailureHandler(){
return (request, response, exception) ->{
request.getSession().setAttribute("flash",
new FlashMessage("Incorrect username and/or password. Try again.",
FlashMessage.Status.FAILURE));
response.sendRedirect("/login");
};
}
@Bean
public EvaluationContextExtension securityExtension(){
return new EvaluationContextExtensionSupport() {
@Override
public String getExtensionId() {
return "security";
}
@Override
public Object getRootObject(){
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication) {
};
}
};
}
}
Вторым является класс сущности User:
@Entity
public class User implements UserDetails{
public static final PasswordEncoder PASSWORD_ENCODER =
new BCryptPasswordEncoder();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Column(unique = true)
@Size(min = 2, max = 20)
private String username;
@NotNull
@Column(length = 100)
@JsonIgnore
private String password;
@NotNull
@Column(length = 100)
@JsonIgnore
private String matchingPassword;
@Column(nullable = false)
private boolean enabled;
@OneToOne
@JoinColumn(name = "role_id")
@JsonIgnore
private Role role;
@ManyToMany(targetEntity = Recipe.class, fetch = FetchType.EAGER)
@JoinTable(name = "users_favorite_recipes",
joinColumns = @JoinColumn(name="user_id"),
inverseJoinColumns = @JoinColumn(name = "recipe_id"))
private List<Recipe> favoritedRecipes = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Recipe> ownedRecipes = new ArrayList<>();
//constructor ...
//getters and setters ...
public void encryptPasswords(){
password = PASSWORD_ENCODER.encode(password);
matchingPassword = PASSWORD_ENCODER.encode(matchingPassword);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(role.getName()));
return authorities;
}
@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 enabled;
}
}
Третий фрагмент представляет интерфейс, который расширяет
UserDetailsService:
public interface UserService extends UserDetailsService{
UserDetails loadUserByUsername(String username);
User findByUsername(String username);
User registerNewUser(String username, boolean enabled, String password, String matchingPassword);
void save(User user);
List<User> findAll();
}
Четвертый и последний фрагмент является реализацией предыдущего
интерфейс (UserService):
@Component
@ComponentScan
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
@Autowired
private RoleDao roleDao;
@Override
public User findByUsername(String username) {
User user = userDao.findByUsername(username);
Hibernate.initialize(user.getFavoritedRecipes());
return user;
}
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException{
User user = userDao.findByUsername(username);
if(user == null){
throw new UsernameNotFoundException(
username + " was not found"
);
}
return user;
}
@Override
public void save(User user) {
userDao.save(user);
}
@Override
public User registerNewUser(String username, boolean enabled, String password, String matchingPassword) {
return userDao.save(new User(username, enabled, password, matchingPassword));
}
@Override
public List<User> findAll() {
return userDao.findAll();
}
}
Что я должен изменить в этой ситуации, чтобы получить функциональную авторизацию REST API?