允许根据用户角色访问控制器。所有这些都出现 403 错误

allow access to controller based on user's role. 403 error on all of them

我正在尝试允许具有特定角色的用户访问我的 Spring 启动应用程序的部门控制器。但是在所有用户角色上都出现 403 错误。我知道我错过了一些东西,但不知道是什么。这是我目前所拥有的:

网络安全配置:

package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
         @Qualifier("userDetailsServiceImpl")
            @Autowired
            private UserDetailsService userDetailsService;
        
         
         @Bean
            public BCryptPasswordEncoder bCryptPasswordEncoder() {
                return new BCryptPasswordEncoder();
            }
    
         @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .authorizeRequests()
                      
                    .antMatchers("/resources/**", "/registration").permitAll()
                    .antMatchers("/department/list").hasRole("ADMIN")
    
                    .anyRequest().authenticated()
                        .and()
                    .formLogin()
                        .loginPage("/login")
                        .permitAll()
                        .and()
                    .logout()
                        .permitAll();
            }
         
         @Bean
            public AuthenticationManager customAuthenticationManager() throws Exception {
                return authenticationManager();
            }
    
         @Autowired
            public void configureGlobal(AuthenticationManagerBuilder auth,AuthenticationManagerBuilder auth2) throws Exception {
                        
                    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
            }

}

我的Users模型如下

    package com.example.model;
    import javax.persistence.*;
    import java.util.Set;
    @Entity
    @Table(name = "users")

  
public class Users {
      @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;
      private String username;
      private String password;
      @Transient
      private String passwordconfirm;
      
      @ManyToMany
        private Set<Roles> roles;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getpasswordconfirm() {
        return passwordconfirm;
    }

    public void setpasswordconfirm(String passwordconfirm) {
        this.passwordconfirm = passwordconfirm;
    }

    public Set<Roles> getRoles() {
        return roles;
    }

    public void setRoles(Set<Roles> roles) {
        this.roles = roles;
    }
      
      
}

角色模型:

package com.example.model;
import javax.persistence.*;
import java.util.Set;

@Entity
@Table(name = "roles")
public class Roles {

     @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;
        
        private String name;
        @ManyToMany(mappedBy = "roles")
        private Set<Users> users;
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Set<Users> getUsers() {
            return users;
        }
        public void setUsers(Set<Users> users) {
            this.users = users;
        }
        
}

这是我的 UsersRepository:

package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.Users;
public interface UsersRepository extends JpaRepository<Users, Integer> {
    Users findByUsername(String username);

}

角色库:

package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.Roles;
public interface RolesRepository extends JpaRepository<Roles, Integer> {

}

我的SecurityService实现如下:

package com.example.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

@Service
public class SecurityServiceImplementation implements SecurityService {
     @Autowired
        private AuthenticationManager authenticationManager;
     @Autowired
        private UserDetailsService userDetailsService;
        private static final Logger logger = 

LoggerFactory.getLogger(SecurityServiceImplementation.class);

        
        @Override
        public String findLoggedInUsername() {
            Object userDetails = 

SecurityContextHolder.getContext().getAuthentication().getDetails();

            if (userDetails instanceof UserDetails) {
                return ((UserDetails)userDetails).getUsername();
            }

            return null;
        }
        
        @Override
        public void autoLogin(String username, String password) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new 

UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());


            authenticationManager.authenticate(usernamePasswordAuthenticationToken);

            if (usernamePasswordAuthenticationToken.isAuthenticated()) {
            

SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

                logger.debug(String.format("Auto login %s successfully!", username));
            }
        }
}

而我的userDetailsS​​ervice如下

package com.example.services;
import com.example.model.Users;
import com.example.model.Roles;
import com.example.repository.UsersRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.Set;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UsersRepository usersRepository;
    
     @Override
        @Transactional(readOnly = true)
        public UserDetails loadUserByUsername(String username) {
            Users user = usersRepository.findByUsername(username);
            if (user == null) throw new UsernameNotFoundException(username);

            Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
            for (Roles roles : user.getRoles()){
                grantedAuthorities.add(new SimpleGrantedAuthority(roles.getName()));
            }

            return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
        }
}

我的用户服务实现:

package com.example.services;
import com.example.model.Users;
import com.example.repository.UsersRepository;
import com.example.repository.RolesRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashSet;

@Service
public class UsersServiceImplementation implements UsersService {
    @Autowired
    private UsersRepository usersRepository;
    @Autowired
    private RolesRepository rolesRepository;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public void save(Users user) {
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        user.setRoles(new HashSet<>(rolesRepository.findAll()));
        usersRepository.save(user);
    }

    @Override
    public Users findByUsername(String username) {
        return usersRepository.findByUsername(username);
    }
}

最后我的控制器如下:

package com.example.controller;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
//import org.springframework.web.bind.annotation.RequestMapping;
//import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.example.model.Users;
import com.example.services.SecurityService;
import com.example.services.UsersService;
import com.example.validators.UsersValidator;

import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
@Controller

@SpringBootApplication

public class IndexController {

     @Autowired
        private UsersService usersService;

        @Autowired
        private SecurityService securityService;

        @Autowired
        private UsersValidator usersValidator;
    
        @GetMapping("/registration")
        public String registration(Model model) {
            model.addAttribute("userForm", new Users());

            return "registration";
        }
        
        @PostMapping("/registration")
        public String registration(@ModelAttribute("userForm") Users userForm, BindingResult 

bindingResult) {

            usersValidator.validate(userForm, bindingResult);

            if (bindingResult.hasErrors()) {
                return "registration";
            }

            usersService.save(userForm);

            securityService.autoLogin(userForm.getUsername(), userForm.getpasswordconfirm());

            return "redirect:/welcome";
        }
        
        @GetMapping("/login")
        public String login(Model model, String error, String logout) {
            if (error != null)
                model.addAttribute("error", "Имя пользователя или пароль не верн.");

            if (logout != null)
                model.addAttribute("message", "Вы успешно вышли из системыy.");

            return "login";
        }
        
        @GetMapping({"/", "/welcome"})
        public String welcome(Model model) {
            return "welcome";
        }
}

为了验证用户,我使用 MySQL 表用户、角色和 users_roles。很抱歉有很多有问题的代码,但我被弄糊涂了,不知道去哪里找。

Login.JSP 如果有帮助:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<c:set var="contextPath" value="${pageContext.request.contextPath}"/>

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="utf-8">
      <title>Вход</title>
 <link href="../../webjars/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />

 <script src="../../webjars/bootstrap/4.0.0/js/bootstrap.min.js"></script>
 <script src="../../webjars/jquery/3.0.0/js/jquery.min.js"></script>
  </head>

  <body>

    <div class="container">
      <form method="POST" action="${contextPath}/login" class="form-signin">
        <h2 class="form-heading">Вход</h2>

        <div class="form-group ${error != null ? 'has-error' : ''}">
            <span>${message}</span>
            <input name="username" type="text" class="form-control" placeholder="Логин"
                   autofocus="true"/>
            <input name="password" type="password" class="form-control" placeholder="Пароль"/>
            <span>${error}</span>
            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

            <button class="btn btn-lg btn-primary btn-block" type="submit">Вход</button>
            <h4 class="text-center"><a href="${contextPath}/registration">Зарегистрироватся</a></h4>
        </div>
      </form>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
 
  </body>
</html>    

如果您查看 hasRole 方法,您会看到它会添加一个 ROLE_ 前缀:

private static String hasRole(String role) {
    Assert.notNull(role, "role cannot be null");
    Assert.isTrue(!role.startsWith("ROLE_"), () -> {
        return "role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'";
    });
    return "hasRole('ROLE_" + role + "')";
}

我怀疑您将您的角色命名为 ADMINMANAGER 并这样使用它们。我建议尝试重命名您的角色并为它们添加 ROLE_ 前缀,例如 ROLE_ADMINROLE_MANAGER 然后重试。

请确保当您 getName() 您的角色名称有一个 ROLE_ 前缀,例如 ROLE_ADMIN

for (Roles roles : user.getRoles()){
    grantedAuthorities.add(new SimpleGrantedAuthority(roles.getName()));

}