Spring Security 总是返回 HTTP 403 访问被拒绝 [关闭]

Posted

技术标签:

【中文标题】Spring Security 总是返回 HTTP 403 访问被拒绝 [关闭]【英文标题】:Spring security always returns HTTP 403 access denied [closed] 【发布时间】:2022-01-16 23:27:32 【问题描述】:

对应用程序进行身份验证后,我在访问应用程序的其他 URL 时遇到问题。我已禁用 csrf,并已添加到 UserDetailsS​​ervice 类的 loadUserByUsername 方法,但问题仍然存在。我使用 Spring Boot 2.5.6,基本身份验证与 JWT 相结合。

spring 安全配置

    @EnableGlobalMethodSecurity(prePostEnabled = true,  securedEnabled = true,jsr250Enabled = true)
@Order(Ordered.HIGHEST_PRECEDENCE)
//@EnableWebSecurity
public class MultiHttpSecurityConfig 

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter 

        private final BCryptPasswordEncoder passwordEncoder;

        private final KalanblowSystemManagementCustomService customService;

        @Autowired
        public ApiWebSecurityConfigurationAdapter(BCryptPasswordEncoder passwordEncoder,
                @Lazy KalanblowSystemManagementCustomService customService) 
            super();
            this.passwordEncoder = passwordEncoder;
            this.customService = customService;
        

        @Override
        protected void configure(AuthenticationManagerBuilder authenticationManager) throws Exception 

            authenticationManager.userDetailsService(customService).passwordEncoder(passwordEncoder);
        

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http.antMatcher("/api/**").authorizeRequests().antMatchers("/api/v1/user/**").permitAll()
                    .anyRequest().authenticated().and().exceptionHandling()
                    .authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED)).and()
                    .addFilter(new ApiJWTAuthenticationFilter(authenticationManager()))
                    .addFilter(new ApiJWTAuthorizationFilter(authenticationManager())).sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            http.httpBasic();
             http.csrf().disable();

        

    

    @Configuration
    @Order(2)
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter 

        private final BCryptPasswordEncoder passwordEncoder;

        private final CustomService customService;

        private final CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

        private final JpaPesristentTokenRepository jpersistentTokenRepository;

        @Autowired
        public FormLoginWebSecurityConfigurerAdapter(BCryptPasswordEncoder passwordEncoder,
                @Lazy CustomService customService,
                CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler,
                JpaPesristentTokenRepository jpersistentTokenRepository

        ) 
            super();
            this.passwordEncoder = passwordEncoder;
            this.customService = customService;
            this.customAuthenticationSuccessHandler = customAuthenticationSuccessHandler;
            this.jpersistentTokenRepository = jpersistentTokenRepository;
        

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception 

            auth.eraseCredentials(true).userDetailsService(customService).passwordEncoder(passwordEncoder);
        

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            
            http.httpBasic();
            http.csrf().disable().authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/images/*").permitAll()
            .antMatchers("/login").permitAll()
            .antMatchers("/users/editeUser/id").hasRole(UserRole.ADMIN.getUserRole())
            .antMatchers("/users/list").hasAnyRole(UserRole.ADMIN.getUserRole(), UserRole.STAFF.getUserRole())
            .antMatchers("/users/**").hasAnyRole(UserRole.ADMIN.getUserRole(), UserRole.STAFF.getUserRole())
            .antMatchers("/user/**").permitAll()
            .antMatchers("/admin/**").hasAnyRole(UserRole.ADMIN.getUserRole(), UserRole.STAFF.getUserRole())
            .antMatchers("/student/**").hasAnyRole(UserRole.ADMIN.getUserRole(), UserRole.STAFF.getUserRole(),UserRole.STUDENT.getUserRole())
                    .anyRequest().authenticated()
                    .and().cors().and()
                    .formLogin()
                    .loginPage("/login").permitAll()
                    .failureUrl("/login?error=true")
                    .usernameParameter("email")
                    .passwordParameter("password")
                    .successHandler(customAuthenticationSuccessHandler)
                    .and()
                    .logout().permitAll()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                    .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                    .deleteCookies("JSESSIONID")
                    .logoutSuccessUrl("/login").and()
                    .exceptionHandling();

            http.rememberMe().key("remember-me").tokenRepository(jpersistentTokenRepository)
                    .userDetailsService(customService).tokenValiditySeconds((int) SecurityConstants.EXPIRATION_TIME);

        

        @Override
        public void configure(WebSecurity web) throws Exception 
            web.ignoring().antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**",
                    "/resources/static/**", "/css/**", "/js/**", "/img/**", "/fonts/**", "/images/**", "/scss/**",
                    "/vendor/**", "/favicon.ico", "/auth/**", "/favicon.png", "/v2/api-docs", "/configuration/ui",
                    "/configuration/security", "/webjars/**", "/swagger-resources/**", "/actuator", "/swagger-ui/**",
                    "/actuator/**", "/swagger-ui/index.html", "/swagger-ui/");
        

        
    
    


**The class that implements UserDetailsService**


@Transactional
public class CustomService implements UserDetailsService 

    private final UserService userService;


    @Autowired
    public CustomService(UserService userService) 
        super();
        this.userService = userService;
        
    

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 

        Optional<UserDto> userDto = Optional.ofNullable(userService.findUserByEmail(username).orElseThrow(
                () -> new UsernameNotFoundException(format("Admin with email %s could not be found", username))));


        if (userDto != null) 
            Set<GrantedAuthority> authorities = getAuthority(userDto.get().getRoles());

            return buildUserForAuthentication(userDto.get(), authorities);
         else 
            throw new UsernameNotFoundException("Admin with email" + username + "does not exist");
        

    

    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

    private UserDetails buildUserForAuthentication(UserDto userDto, Set<GrantedAuthority> authorities) 

        return new User(userDto.getEmail(), userDto.getPassword(), enabled, accountNonExpired, credentialsNonExpired,
                accountNonLocked, authorities);
    

    private Set<GrantedAuthority> getAuthority(Set<RoleDto> roleDtos) 

        Set<GrantedAuthority> roles = new HashSet<>();
        roleDtos.forEach((role) -> 

            roles.add(new SimpleGrantedAuthority(role.getUserRoleName()));
            
             
        );
        return new HashSet<>(roles);
    



**User Controller class**

    @Controller
@Slf4j
@RequestMapping("/users")
public class UserController 

    public static final String EDIT_USER_FORM = "users/editeUser";

    public static final String REDIRECT_ADMIN_PAGE_USERS = "redirect:/users/allUsers";

    @Autowired
    private UserService userService;

    private UserFinder userFinder;

    private UserSearchErrorResponse userSearchErrorResponse;

    @Autowired
    private RoleService roleService;

    @Autowired
    private BCryptPasswordEncoder passworEncoder;

    private ModelMapper modelMapper;

    /**
     * Get all users or search users if searching parameters exist
     * 
     * @param pageable
     * @return
     */
    @GetMapping("/list")
    @PreAuthorize("hasRole('ADMIN')and hasRole('TEACHER') and hasRole('STAFF')")
    //@PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'ADMIN')")
    //@Secured("ADMIN")
    public ModelAndView getUsersList(ModelAndView modelAndView, UserSearchParameters userSearchParameters) 

        modelAndView = new ModelAndView("users/allUsers");

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        Optional<UserDto> userDto = userService.findUserByEmail(authentication.getName());

        // page size
        if (userSearchParameters.getPage().isPresent()) 
            Optional<Integer>  selectedPageSize = Optional.ofNullable(userSearchParameters.getPageSize().orElse(InitialPagingSizes.INITIAL_PAGE_SIZE));
            // Evaluate page size. If requested parameter is null, return initial
            Optional<Integer> selectedPage = Optional.ofNullable((userSearchParameters.getPage().orElse(0) < 1) ? InitialPagingSizes.INITIAL_PAGE
                    : (userSearchParameters.getPage().get() - 1));
            PageRequest pageRequest = PageRequest.of(Integer.valueOf(selectedPage.get()),Integer.valueOf( selectedPageSize.get()), Sort.by(Direction.ASC, "id"));
            UserSearchResult userSearchResult = new UserSearchResult();

            if (userSearchParameters.getPropertyValue().isEmpty()
                    || userSearchParameters.getPropertyValue().get().isEmpty()) 
                userSearchResult.setUserPage(userService.listUserByPage(pageRequest));
             else 

                userSearchResult = userFinder.searchUsersByProperty(pageRequest, userSearchParameters);

                if (userSearchResult.isNumberFormatException()) 

                    return userSearchErrorResponse.respondToNumberFormatException(userSearchResult, modelAndView);
                

                if (userSearchResult.getUserPage().getTotalElements() == 0) 

                    modelAndView = userSearchErrorResponse.respondToEmptySearchResult(modelAndView, pageRequest);
                    userSearchResult.setUserPage(userService.findAllPageable(pageRequest));
                

                modelAndView.addObject("usersProperty", userSearchParameters.getUsersProperty().get());
                modelAndView.addObject("propertyValue", userSearchParameters.getPropertyValue().get());
            

            Pager pager = new Pager(userSearchResult.getUserPage().getTotalPages(),
                    userSearchResult.getUserPage().getNumber(), InitialPagingSizes.BUTTONS_TO_SHOW,
                    userSearchResult.getUserPage().getTotalElements());
            modelAndView.addObject("pager", pager);
            modelAndView.addObject("users", userSearchResult.getUserPage());
            modelAndView.addObject("selectedPageSize", selectedPageSize);
            modelAndView.addObject("pageSizes", InitialPagingSizes.PAGE_SIZES);
        


        if (userDto.isPresent()) 
            modelAndView.addObject("userName", userDto.get());
            modelAndView.addObject("authorithy", userDto.get().getRoles());
        


        return modelAndView;
    



所有用户的视图

   <!DOCTYPE html>
    <html lang="fr" xmlns:th="http://www.thymeleaf.org"
        xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
        xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
         th:with="activeMenuItem='users'">
    <head th:replace="fragments/header :: header">
    <title>user</title>
    </head>
    <body style="background: #4f5050">
        <div th:insert="fragments/sidebar :: sidebar"></div>
    
        <!-- ============================================================== -->
        <!-- Container fluid  -->
        <!-- ============================================================== -->
        <div class="container-fluid" th:insert="fragments/navigation">
            <h1 th:text="#user.all" class="page-titles display-flex-center"></h1>
        </div>
        <div class="container" id="mainContainer">
            <!-- ============================================================== -->
            <!-- Bread crumb and right sidebar toggle -->
            <!-- ============================================================== -->
    
            <!-- ============================================================== -->
            <!-- End Bread crumb and right sidebar toggle -->
            <!-- ============================================================== -->
            <!-- ============================================================== -->
            <!-- Start Page Content -->
            <!-- ============================================================== -->
            <!-- Row -->
    
            <!-- tag::create-button[] -->
            <div
                th:replace="fragments/titles :: title-with-button(#user.title, 'user-add', #user.add, @/user/signup)"
                sec:authorize="hasRole('ADMIN')"></div>
            <!-- end::create-button[] -->
            <!-- tag::alert[] -->
            <div th:if="$deletedUserName">
                <!--.-->
                <div
                    th:replace="fragments/alerts :: success(#user.delete.success($deletedUserName))"></div>
                <!--.-->
            </div>
            <!-- end::alert[] -->
            <div>
    
                <!--Search user-->
                <div class="row col-lg-12 d-flex flex-nowrap pb-2">
                    <div class="input-group">
                        <select class="custom-select" id="search-user-dropdown"
                            onchange="saveSearchParameters(this);">
                            <option value="ID">ID</option>
                            <option value="fullName">fullName</option>
                            <option value="Email">Email</option>
                        </select> <input type="text" id="searchUserBar"
                            onkeyup='saveSearchParameters(this);'
                            placeholder="Search for user.." class="form-control"
                            aria-label="Text input with dropdown button">
                    </div>
                    <button type="button" class="btn btn-secondary ml-2"
                        onclick="searchUserByProperty()">Search</button>
                </div>
    
                <!--Table with user-->
                <div th:if="$users.isEmpty()">[[#no.user]]</div>
                <div class="table-responsive .table-responsive"
                    th:unless="$users.isEmpty()" id="mainContainerRepleace">
    
                    <table class="table">
                        <thead>
                            <tr>
                                <th onclick="sortTable(0)" scope="col"
                                    th:replace="fragments/table :: header(#label.user.id)"></th>
                                <th onclick="sortTable(1)" scope="col"
                                    th:replace="fragments/table :: header(#user.headers.firstName)"></th>
                                <th onclick="sortTable(2)" scope="col"
                                    th:replace="fragments/table :: header(#user.headers.lastName)"></th>
                                <th onclick="sortTable(3)" scope="col"
                                    th:replace="fragments/table :: header(#user.headers.email)"></th>
                                <th onclick="sortTable(4)" scope="col"
                                    th:replace="fragments/table :: header(#user.headers.mobileNumber)"></th>
                                <th onclick="sortTable(5)" scope="col"
                                    th:replace="fragments/table :: header(#label.user.birthDate)"></th>
                                <th onclick="sortTable(6)" scope="col"
                                    th:replace="fragments/table :: header(#label.user.password)"></th>
                                <th onclick="sortTable(7)" scope="col"
                                    th:replace="fragments/table :: header(#label.user.confirmPass)"></th>
                                <th onclick="sortTable(8)" scope="col"
                                    th:replace="fragments/table :: header(#user.roles)"></th>
                                <th onclick="sortTable(9)" scope="col"
                                    th:replace="fragments/table :: header(#header.address.list)"></th>
                                <th scope="col"
                                    th:replace="fragments/table :: header(#user.del)"></th>
                                <th scope="col"
                                    th:replace="fragments/table :: header(#user.edit)"></th>
                            </tr>
                        </thead>
                        <tbody align="center">
                            <tr th:each="user : $users" class="table-primary">
                                <td class="table-primary" scope="col"
                                    th:replace="fragments/table ::data(contents=$user.id,primary=true)"></td>
                                <td class="
                                    table-secondary" scope="col"
                                    th:replace="fragments/table :: data($user.firstName)"></td>
                                <td class="table-success" scope="col"
                                    th:replace="fragments/table :: data($user.lastName)"></td>
                                <td class="table-danger" scope="col"
                                    th:replace="fragments/table :: data($user.email)"></td>
                                <td class="table-warning" scope="col"
                                    th:replace="fragments/table :: data($user.mobileNumber)"></td>
                                <td class="table-info" scope="col"
                                    th:replace="fragments/table :: data($user.birthDate)"></td>
                                <td class="table-light" scope="col"
                                    th:replace="fragments/table :: data($user.password)"></td>
                                <td class="table-dark" scope="col"
                                    th:replace="fragments/table :: data($user.matchingPassword)"></td>
                                <td class="table-secondary"
                                    th:replace="fragments/table :: data($user.roles)"></td>
                                <td>
                                    <p th:each="address : $user.adresse">
                                        <span th:text="$address.street">Street</span> <span
                                            th:text="$address.streetNumber">Street Number</span> <span
                                            th:text="$address.city">City</span> <span
                                            th:text="$address.codePostale">ZIP</span> <span
                                            th:text="$address.state">State</span> <span
                                            th:text="$address.country">country</span>
                                    </p>
                                </td>
                                <!-- <td th:switch="$u/editeUser/(id=$user.idser.enabled"><span th:case="true"
                                    style="color: green">Enabled</span> <span th:case="false"
                                    style="color: red">Disabled</span></td> -->
    
                                <!--Remove user button-->
                                <!-- tag::td-admin[] -->
                                <th:block sec:authorize="hasRole('ADMIN')">
                                    <!--.-->
                                    <td
                                        th:replace="fragments/table :: dataWithLink('Remove user', @'/users/' +'deleteUser/'+$user.id)"><a
                                        id="remove-link" style="text-decoration: none; color: red"
                                        data-toggle='modal' data-target='#deleteModal'
                                        data-placement="right"
                                        th:onclick="'setRowIndexAndUserId(this, ' + $user.id + ')'">
                                            <i class="fa fa-times" aria-hidden="true"></i>
    
                                    </a></td>
                                    <!--Edit user button-->
                                    <td
                                        th:replace="fragments/table :: dataWithLink('Edit', @'/users/' + 'editeUser/' + $user.id)"><a
                                        style="text-decoration: none; color: blue" class="editBtn"
                                        data-toggle="tooltip" data-placement="right" title="Edit user">
                                            <i class="fa fa-edit"></i>
                                    </a></td>
                                </th:block>
                                <!-- end::td-admin[] -->
                        </tbody>
                    </table>
                    <div th:replace="fragments/deleteUserModal :: delete-user-modal"></div>
                    <!-- <div th:replace="fragments/pagination :: controls(page=$user)"></div> -->
                    <div class="col-lg-3 pl-0">
                        <!--Delete success message-->
                        <div id="alert-messages"></div>
    
                        <!--Save success message-->
                        <div th:if="$userHasBeenSaved"
                            class="alert alert-success alert-dismissible fade show"
                            role="alert">
                            <button type="button" class="close" data-dismiss="alert"
                                aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                            <strong>Well done!</strong> User has been saved!!!
                        </div>
    
                        <!--Update success message-->
                        <div th:if="$userHasBeenUpdated"
                            class="alert alert-success alert-dismissible fade show"
                            role="alert">
                            <button type="button" class="close" data-dismiss="alert"
                                aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                            <strong>Well done!</strong> User has been updated!!!
                        </div>
    
                        <!--Number format exception message-->
                        <div th:if="$numberFormatException"
                            class="alert alert-danger alert-dismissible fade show"
                            role="alert">
                            <button type="button" class="close" data-dismiss="alert"
                                aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                            Please enter a valid number
                        </div>
    
                        <!--No matches found message-->
                        <div th:if="$noMatches"
                            class='alert alert-info alert-dismissible fade show' role='alert'>
                            <button type='button' class='close' data-dismiss='alert'
                                aria-label='Close'>
                                <span aria-hidden='true'>&times;</span>
                            </button>
                            Sorry, no matches found for <span th:text="$userProperty"></span>
                            = <span th:text="$propertyValue"></span>
                        </div>
                    </div>
                </div>
                <a href="#" th:href="@/users/signup"
                    sec:authorize="hasRole('ADMIN')">>
                    <button type="button" class="btn btn-primary">New User</button>
                </a>
    
                <!--Paging-->
                <div id="paging-section" class="row" style="margin-top: 10px;">
    
                    <!--Page size dropdown-->
                    <div class="form-group col-md-1" th:if="$users.totalPages != 0">
    
                        <!--Get pageSizesToShow-->
                        <div hidden id="pageSizesToShow"
                            th:attr="data-pageSizesToShow = $pager.pageSizesToShowInJSON"></div>
    
                        <select class="form-control pagination" id="pageSizeSelect">
                            <option th:each="pageSize : $pageSizes" th:text="$pageSize"
                                th:value="$pageSize"
                                th:selected="$pageSize == $selectedPageSize"></option>
                        </select>
                    </div>
    
                    <!--Pages-->
                    <nav aria-label="Page navigation example"
                        class="form-group col-md-11 pagination-centered">
                        <ul class="pagination" th:if="$users.totalPages != 0">
                            <li th:class="$users.number == 0 ? 'page-item disabled'"
                                class="page-item"><a
                                th:if="$not #strings.isEmpty(propertyValue)" class="page-link"
                                th:href="@/users(userProperty=$userProperty,
                                           propertyValue=$propertyValue, pageSize=$selectedPageSize, page=1)">
                                    &laquo; </a> <a th:if="$#strings.isEmpty(propertyValue)"
                                class="page-link"
                                th:href="@/users/user(pageSize=$selectedPageSize, page=1)">
                                    &laquo; </a></li>
                            <li th:class="$users.number == 0 ? 'page-item disabled'"
                                class="page-item"><a
                                th:if="$not #strings.isEmpty(propertyValue) " class="page-link"
                                th:href="@/users(userProperty=$userProperty,
                                           propertyValue=$propertyValue, pageSize=$selectedPageSize, page=$users.number)">
                                    &larr; </a> <a th:if="$#strings.isEmpty(propertyValue)"
                                class="page-link"
                                th:href="@/users/user(pageSize=$selectedPageSize, page=$user.number)">
                                    &larr; </a></li>
                            <li
                                th:class="$users.number == (page - 1) ? 'active pointer-disabled'"
                                class="page-item"
                                th:each="page : $#numbers.sequence(pager.startPage, pager.endPage)">
                                <a th:if="$not #strings.isEmpty(propertyValue)"
                                class="page-link"
                                th:href="@/users(userProperty=$userProperty,
                                           propertyValue=$propertyValue, pageSize=$selectedPageSize, page=$page)"
                                th:text="$page"> </a> <a
                                th:if="$#strings.isEmpty(propertyValue)" class="page-link"
                                th:href="@/users(pageSize=$selectedPageSize, page=$page)"
                                th:text="$page"> </a>
                            </li>
                            <li
                                th:class="$users.number + 1 == users.totalPages ? 'page-item disabled'"
                                class="page-item"><a
                                th:if="$not #strings.isEmpty(propertyValue)" class="page-link"
                                th:href="@/users(userProperty=$userProperty,
                                           propertyValue=$propertyValue, pageSize=$selectedPageSize, page=$users.number + 2)">
                                    &rarr; </a> <a th:if="$#strings.isEmpty(propertyValue)"
                                class="page-link"
                                th:href="@/users(pageSize=$selectedPageSize, page=$users.number + 2)">
                                    &rarr; </a></li>
                            <li
                                th:class="$users.number + 1 == users.totalPages ? 'page-item disabled'"
                                class="page-item"><a
                                th:if="$not #strings.isEmpty(propertyValue) " class="page-link"
                                th:href="@/users(userProperty=$userProperty, propertyValue=$propertyValue,
                                           pageSize=$selectedPageSize, page=$users.totalPages)">
                                    &raquo; </a> <a th:if="$#strings.isEmpty(propertyValue)"
                                class="page-link"
                                th:href="@/users(pageSize=$selectedPageSize, page=$users.totalPages)">
                                    &raquo; </a></li>
                        </ul>
                    </nav>
                </div>
    
            </div>
        </div>
        <div th:replace="~fragments/footer :: footer"></div>
    
    </body>
    </html>

拜托,你能帮帮我吗?

【问题讨论】:

UserRole.ADMIN.getUserRole()==ADMIN 和 UserRole.STAFF.getUserRole()== STAFF 然后添加 Spring Security 日志,它包含原因。首先你必须改变你的日志配置才能看到 Spring Security 的日志。 我添加了日志,但我没有理由拒绝访问 url。 您确定用户必须拥有所有 3 个角色吗? @PreAuthorize("hasRole('ADMIN')and hasRole('TEACHER') and hasRole('STAFF')")您遇到的问题是哪个网址,哪个有效? 您是否在日志中修复了 NullPointerException?显示您的新日志。 【参考方案1】:

您确定用户必须在此处拥有所有 3 个角色吗? @PreAuthorize("hasRole('ADMIN')and hasRole('TEACHER') and hasRole('STAFF')")您遇到的问题是哪个 URL,哪个有效?

在你的配置中你说:

.antMatchers("/users/**").hasAnyRole(UserRole.ADMIN.getUserRole(), UserRole.STAFF.getUserRole())

但在您的 @PreAuthorize 中,您要求用户拥有所有 3 个角色

【讨论】:

我有超过 3 个角色,但根据 url,我有一些角色可以访问或不可以访问,这就是为什么在 localhost:8080/users/list 只有 ADMIN 和 STAFF 可以访问它们 不读取 ADMIN 和 STAFF,读取:同时具有所有 ADMIN 和 STAFF 以及 TEACHER 角色的用户。您的用户是否拥有所有这 3 个角色? 我有一个角色层次结构 ADMIN>STAFF>TEACHER>USER 我的用户具有访问 url 的 ADMIN 角色。 您好 ACV,非常感谢您的关注,我解决了我的 nullpointer 异常,这是一个日志错误:] osswaiFilterSecurityInterceptor : 无法授权过滤器调用 [GET /users/list] 属性 [hasAnyRole( 'ROLE_ADMIN')] 2021-12-16 11:36:44.249 调试 381671 --- [http-nio-8080-exec-5] osswaccess.AccessDeniedHandlerImpl :响应 403 状态码

以上是关于Spring Security 总是返回 HTTP 403 访问被拒绝 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security + LDAP 总是返回 BadCredentialsException

登录后 Spring Security 总是返回 403 accessDeniedPage [重复]

Spring Security Granted Authorities 总是返回空

Spring Security 总是返回 403 被禁止,访问被拒绝

在 Spring Security 5.1.6 中,logout-success-url 总是重定向到 HTTP 而不是 HTTPS

$ http get使用AngularJS返回html而不是JSON Object Spring Security