Spring Boot中的Spring安全配置未按预期工作[重复]

Posted

技术标签:

【中文标题】Spring Boot中的Spring安全配置未按预期工作[重复]【英文标题】:Spring security configuration in spring boot not working as expected [duplicate] 【发布时间】:2021-11-23 11:41:34 【问题描述】:

我正在使用带有 Spring Boot 的 Spring Security。但我的 spring 安全配置现在按预期工作。

注意:H2 数据库在服务器模式下作为单独的数据库运行(不在嵌入式模式下)。

这是我的项目详情:

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

Application.properties

server.port=8085

spring.datasource.url=jdbc:h2:tcp://localhost:9092/mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
    

EmployeeeResource.java

@RestController
@RequestMapping("/employee")
@Slf4j
public class EmployeeResource 

    @Autowired
    EmployeeRepository employeeRepository;

    @GetMapping(path = "/greetEmployee", produces = MediaType.TEXT_PLAIN_VALUE)
    public String sayHello() 
        return "Hello Employee !!!";
    

    @GetMapping(path = "/getAllEmployees", produces = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<List<Employee>> getAllEmployee() 
        List<Employee> employeeList = employeeRepository.findAll();
        return new ResponseEntity<>(employeeList, HttpStatus.OK);
    

    @GetMapping(path = "/getEmployee/employeeId", produces = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<Employee> getEmployee(@PathVariable("employeeId") int employeeId) 
        Optional<Employee> optionalEmployee = employeeRepository.findByEmployeeId(employeeId);
        if (optionalEmployee.isEmpty()) 
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        
        return new ResponseEntity<>(optionalEmployee.get(), HttpStatus.FOUND);
    

    @PostMapping(path = "/createEmployee", consumes = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<HttpStatus> createEmployee(@RequestBody Employee employee) 
        Random random = new Random();
        employee.setEmployeeId(random.nextInt(9999));
        employeeRepository.save(employee);
        log.info("Created employee with Id : ", employee.getEmployeeId());

        return new ResponseEntity<>(HttpStatus.CREATED);
    

    @PostMapping(path = "/createEmployees", consumes = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<String> createEmployees(@RequestBody List<Employee> employeeList) 
        int count = 0;
        Random random = new Random();
        for (Employee employee : employeeList) 
            employee.setEmployeeId(random.nextInt(999999));
            employeeRepository.save(employee);
            log.info("Created employee with Id : ", employee.getEmployeeId());
            count++;
        
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.set("countOfObjectCreated", String.valueOf(count));
        return ResponseEntity.status(HttpStatus.CREATED).headers(responseHeaders).build();
    

    @PutMapping(path = "/updateEmployee/employeeId", consumes = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<HttpStatus> updateCustomer(@PathVariable("employeeId") int employeeId, @RequestBody Employee employee) 
        Optional<Employee> optionalDbEmployee = employeeRepository.findByEmployeeId(employeeId);
        if (optionalDbEmployee.isEmpty()) 
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        
        Employee dbEmployee = optionalDbEmployee.get();
        dbEmployee.setFirstName(employee.getFirstName());
        dbEmployee.setLastName(employee.getLastName());
        dbEmployee.setExtension(employee.getExtension());
        dbEmployee.setEmail(employee.getEmail());
        dbEmployee.setOfficeCode(employee.getOfficeCode());
        dbEmployee.setReportsTo(employee.getReportsTo());
        dbEmployee.setJobTitle(employee.getJobTitle());
        return new ResponseEntity<>(HttpStatus.OK);
    

    @DeleteMapping(path = "/deleteEmployee/employeeId")
    public ResponseEntity<HttpStatus> deleteCustomer(@PathVariable("employeeId") int employeeId) 
        employeeRepository.deleteById(employeeId);
        log.info("Employee with employee id  Deleted successfully.", employeeId);
        return new ResponseEntity<>(HttpStatus.OK);
    

Employee.java

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
@Entity
@Table(name = "EMPLOYEE")
public class Employee 

    @Id
    @Column(name = "EMPLOYEE_ID")
    int employeeId;

    @Column(name = "LAST_NAME")
    String lastName;

    @Column(name = "FIRST_NAME")
    String firstName;

    @Column(name = "EXTENSION")
    String extension;

    @Column(name = "EMAIL")
    String email;

    @Column(name = "OFFICE_CODE")
    int officeCode;

    @Column(name = "REPORTS_TO")
    Integer reportsTo;

    @Column(name = "JOB_TITLE")
    String jobTitle;

OfficeResource.java

@RestController
@RequestMapping("/office")
@Slf4j
public class OfficeResource 

    @Autowired
    OfficeRepository officeRepository;

    @GetMapping(path = "/greetOffice", produces = MediaType.TEXT_PLAIN_VALUE)
    public String sayHello() 
        return "Hello Office !!!";
    

    @GetMapping(path = "/getAllOffices", produces = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<List<Office>> getAllOffices() 
        List<Office> officeList = officeRepository.findAll();
        return new ResponseEntity<>(officeList, HttpStatus.OK);
    

    @GetMapping(path = "/getOffice/officeCode", produces = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<Office> getOffice(@PathVariable("officeCode") int officeCode) 
        Optional<Office> optionalOffice = officeRepository.findByOfficeCode(officeCode);
        if (optionalOffice.isEmpty()) 
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        
        return new ResponseEntity<>(optionalOffice.get(), HttpStatus.FOUND);
    

    @PostMapping(path = "/createOffice", consumes = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<HttpStatus> createOffice(@RequestBody Office office) 
        Random random = new Random();
        office.setOfficeCode(random.nextInt(999));
        officeRepository.save(office);
        log.info("Created office with office code : ", office.getOfficeCode());

        return new ResponseEntity<>(HttpStatus.CREATED);
    

    @PostMapping(path = "/createOffices", consumes = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<String> createOffices(@RequestBody List<Office> officeList) 
        int count = 0;
        Random random = new Random();
        for (Office office : officeList) 
            office.setOfficeCode(random.nextInt(999));
            officeRepository.save(office);
            log.info("Created office with office code : ", office.getOfficeCode());
            count++;
        
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.set("countOfObjectCreated", String.valueOf(count));
        return ResponseEntity.status(HttpStatus.CREATED).headers(responseHeaders).build();
    

    @PutMapping(path = "/updateOffice/officeCode", consumes = MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<HttpStatus> updateOffice(@PathVariable("officeCode") int officeCode, @RequestBody Office office) 
        Optional<Office> optionalDbOffice = officeRepository.findByOfficeCode(officeCode);
        if (optionalDbOffice.isEmpty()) 
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        
        Office dbOffice = optionalDbOffice.get();
        dbOffice.setCity(office.getCity());
        dbOffice.setPhone(office.getPhone());
        dbOffice.setAddressLine1(office.getAddressLine1());
        dbOffice.setAddressLine2(office.getAddressLine2());
        dbOffice.setState(office.getState());
        dbOffice.setCountry(office.getCountry());
        dbOffice.setPostalCode(office.getPostalCode());
        dbOffice.setTerritory(office.getTerritory());

        return new ResponseEntity<>(HttpStatus.OK);
    

    @DeleteMapping(path = "/deleteOffice/officeCode")
    public ResponseEntity<HttpStatus> deleteOffice(@PathVariable("officeCode") int officeCode) 
        officeRepository.deleteById(officeCode);
        log.info("Office with office code  Deleted successfully.", officeCode);
        return new ResponseEntity<>(HttpStatus.OK);
    

Office.java

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
@Entity
@Table(name = "OFFICE")
public class Office 

    @Id
    @Column(name = "OFFICE_CODE")
    int officeCode;

    @Column(name = "CITY")
    String city;

    @Column(name = "PHONE")
    String phone;

    @Column(name = "ADDRESS_LINE1")
    String addressLine1;

    @Column(name = "ADDRESS_LINE2")
    String addressLine2;

    @Column(name = "STATE")
    String state;

    @Column(name = "COUNTRY")
    String country;

    @Column(name = "POSTAL_CODE")
    String postalCode;

    @Column(name = "TERRITORY")
    String territory;

SecurityConfiguration.java

    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter 
    
        @Autowired
        DataSource dataSource;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception 
            auth.jdbcAuthentication()
                    .dataSource(dataSource)
                    .usersByUsernameQuery("select username,password,enabled from users where username = ?")
                    .authoritiesByUsernameQuery("select username,authority from authorities where username = ?")
                    .passwordEncoder(NoOpPasswordEncoder.getInstance());
        
    
        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http.authorizeRequests()
                    .antMatchers("/employee/createEmployee", "/employee/createEmployees", "/employee/updateEmployee/**", "/employee/deleteEmployee/**").hasRole("Admin")
                    .antMatchers("/office/createOffice", "/office/createOffices", "/office/updateOffice/**", "/office/deleteOffice/**").hasRole("Admin")
                    .antMatchers("/employee/getEmployee/**", "/employee/getAllEmployees").hasAnyRole("Admin","User")
                    .antMatchers("/office/getOffice/**", "/office/getAllOffices").hasAnyRole("Admin","User")
                    .and().formLogin();
    
        

从浏览器中点击 url“http://localhost:8085/employee/getEmployee/1002”后,我得到了登录表单,在输入“Admin”用户“User1”的凭据后,得到“Forbidden”, status=403" 错误。

需要帮助。

【问题讨论】:

【参考方案1】:

hasRolehasAnyRole 在您的字符串前面加上 ROLE_。请改用hasAuthoritiyhasAnyAuthority。见spring docs

【讨论】:

进行更改后,我可以使用“User1”和“User2”成功访问任何需要“Admin”或“User”权限的端点。但是在访问任何只需要“Admin”权限的端点时,“User1”被配置为具有“Admin”权限;我收到“禁止,状态=403”错误。

以上是关于Spring Boot中的Spring安全配置未按预期工作[重复]的主要内容,如果未能解决你的问题,请参考以下文章

漫谈Spring Security 在Spring Boot 2.x endpoints中的应用

Spring Boot 安全性中的 HTTP 403 禁止错误

Spring Boot 中的全局方法安全性

Spring Boot 配置问题中的 JWT 令牌

Spring Boot:禁用安全自动配置

Spring Boot 和安全性中的 CORS 支持