2

我有一个我不太明白的错误。我没有找到任何解释为什么它不起作用的教程。我有这个使用spring security的spring boot应用程序。

当我发出这个 POST 请求时:http://localhost:8181/roles 正文:

{
    "name":"ROLE_USER"
} 

它工作正常。

当我发出这个 POST 请求时:http://localhost:8181/users 正文:

 {
    "username":"user",
    "password":"pass",
    "roles":[
      "http://localhost:8181/roles/1"
    ]
} 

它工作正常

但是当我发出这个 GET 请求时:http://localhost:8181/users 具有正确的凭据(用户名:用户,密码:pass)

它返回:

{
  "timestamp": "2020-04-22T15:04:55.032+0000",
  "status": 403,
  "error": "Forbidden",
  "message": "Forbidden",
  "path": "/users"
}

我不知道为什么它会返回 403。

PS:所有请求都在 Postman 上完成

UnoApplication.java

package com.example.Uno;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@SpringBootApplication
public class UnoApplication {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    public static void main(String[] args) {
        SpringApplication.run(UnoApplication.class, args);
    }
}

用户.java

package com.example.Uno.entity;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.util.*;

@Data
@Entity

public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;
    private String password;


    @ManyToMany(mappedBy = "users",targetEntity = Role.class,cascade = {CascadeType.MERGE,CascadeType.PERSIST}, fetch = FetchType.EAGER)
    private Set<Role> roles = new HashSet<>();


}

角色.java

package com.example.Uno.entity;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.util.*;

@Data
@Entity

public class Role implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @ManyToMany(cascade = {CascadeType.MERGE,CascadeType.PERSIST}, fetch = FetchType.LAZY)
    private Set<User> users = new HashSet<>();


}


MyUserDetails.java

package com.example.Uno.entity;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;


public class MyUserDetails implements UserDetails {

    private String username;
    private String password;
    private List<GrantedAuthority> grantedAuthorities;

    public MyUserDetails(com.example.Uno.entity.User user){
        this.username = user.getUsername();
        this.password = user.getPassword();
        for (Role r: user.getRoles()){
            grantedAuthorities.add(new SimpleGrantedAuthority(r.getName()));
        }

    }


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return grantedAuthorities;
    }

    @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;
    }
}

用户存储库.java

package com.example.Uno.repository;


import com.example.Uno.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import java.util.Optional;


@RepositoryRestResource
public interface UserRepository extends JpaRepository<User,Long> {

    User findUserByUsername(String s);

}

RoleRepository.java

package com.example.Uno.repository;

import com.example.Uno.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource
public interface RoleRepository extends JpaRepository<Role,Long> {
    Role findRoleByName(String name);
}

MyUserDetailsS​​ervice.java

package com.example.Uno.service;

import com.example.Uno.entity.MyUserDetails;
import com.example.Uno.entity.User;
import com.example.Uno.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;


@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        User user = userRepository.findUserByUsername(s);
        return new MyUserDetails(user);
    }
}

安全配置.java

package com.example.Uno.config;

import com.example.Uno.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.POST,"/users");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                .antMatchers("/users").hasRole("USER")
                .anyRequest().permitAll().and().httpBasic();
    }
}

感谢您的时间。

编辑

我在 application.properties 中添加了这一行:logging.level.org.springframework.security=DEBUG

当我发出之前的 GET 请求时,它在后端看起来像这样: Spring part 2 User Role

4

1 回答 1

1

所以根据日志

com.example.Uno.entity.MyUserDetails@1c6f2612; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Not granted any authorities'

您的用户详细信息没有任何权限,这意味着方法:findUserByUserName 没有将任何角色添加到用户对象中。或者您需要使用其他函数:findRoleByName() 单独查询角色,并将其设置为 userdetails。

你的方向是正确的,并且非常接近胜利!

于 2020-04-23T13:07:09.070 回答