繁体   English   中英

在Spring Boot中授予或限制通过Spring Security中的角色进行路由的权限

[英]Grant or restrict permissions to routes through roles in Spring Security in Spring Boot

我有一个Spring应用程序,在其中实现了Boot Spring Security。 登录后,我已经成功登录并可以访问所有路由,并且在会话尚未启动时也可以访问所有路由。 在我的系统中,我有一个用户->角色-> Roles_Menu和Menu的列表,如下图所示:

连结图片

我想知道是否可以仅对数据库中注册的路由授予每个角色权限。

尽管在Spring Security的实现中为每个用户都包括了一个路由列表,但这并没有限制那些访问权限未反映在所述列表中的路由。

这是我的代码的详细信息:

这是我的用户课

package com.escuelaapp.EscuelaApp.entity;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

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

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 *
 * @author ALEJO
 */
@Entity
@Table(name = "user")
public class User implements UserDetails{

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @Column(name = "document")
    private long document;
    @Basic(optional = false)
    @Column(name = "first_name")
    private String firstName;
    @Column(name = "second_name")
    private String secondName;
    @Basic(optional = false)
    @Column(name = "surname")
    private String surname;
    @Column(name = "second_surname")
    private String secondSurname;
    @Basic(optional = false)
    @Column(name = "username")
    @NotNull
    @Size(min=2,max=10) 
    private String userName;
    @Column(name = "email")
    private String email;
    @Basic(optional = false)
    @Column(name = "password")
    @NotNull
    private String password;
    @Basic(optional = false)
    @Column(name = "state")
    private short state;

    @JoinColumn(name="profile_id")
    @ManyToOne(targetEntity=Profile.class,fetch=FetchType.EAGER)
    private Profile profile;


    public User() {
    }

    public User(Integer id) {
        this.id = id;
    }

    public User(Integer id, long document, String firstName, String surname, String username, String password,
            short state) {
        this.id = id;
        this.document = document;
        this.firstName = firstName;
        this.surname = surname;
        this.userName = username;
        this.password = password;
        this.state = state;
    }



    public User(@NotNull @Size(min = 2, max = 10) String userName, @NotNull String password) {
        super();
        this.userName = userName;
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

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

    public long getDocument() {
        return document;
    }

    public void setDocument(long document) {
        this.document = document;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getSecondName() {
        return secondName;
    }

    public void setSecondName(String secondName) {
        this.secondName = secondName;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getSecondSurname() {
        return secondSurname;
    }

    public void setSecondSurname(String secondSurname) {
        this.secondSurname = secondSurname;
    }

    public String getUserName() {
        return userName;
    }

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

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @JsonIgnore
    public String getPassword() {
        return password;
    }

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

    public short getState() {
        return state;
    }

    public void setState(short state) {
        this.state = state;
    }

    public Profile getProfile() {
        return profile;
    }

    public void setProfile(Profile profile) {
        this.profile = profile;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", document=" + document + ", firstName=" + firstName + ", secondName=" + secondName
                + ", surname=" + surname + ", secondSurname=" + secondSurname + ", userName=" + userName + ", email="
                + email + ", password=" + password + ", state=" + state + ", profile=" + profile + "]";
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getUsername() {
        return this.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return true;
    }
}

这是配置文件类(或ROL)

package com.escuelaapp.EscuelaApp.entity;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name="profile")
public class Profile {

    @Id
    @Column(name="id")
    private int id;

    @Column(name="name")
    private String name;

    @OneToMany(mappedBy="profile")
    private List<User> users;


    @OneToMany(fetch=FetchType.EAGER,mappedBy="profileId")
    private List<ProfileMenu> profileMenus;

    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;
    }
    @Transient
    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
    @Transient
    public List<ProfileMenu> getProfileMenus() {
        return profileMenus;
    }

    public void setProfileMenus(List<ProfileMenu> profileMenus) {
        this.profileMenus = profileMenus;
    }

    @Override
    public String toString() {
        return "Profile [id=" + id + ", name=" + name + ", users=" + users + "]";
    }   
}

这是菜单类

package com.escuelaapp.EscuelaApp.entity;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name = "menu")
public class Menu {

    @Id
    @Column(name = "id")
    private int id;
    @Column(name = "name")
    private String name;
    @Column(name = "url")
    private String url;
    @Column(name = "icon")
    private String icon;

    @OneToMany( mappedBy = "menus")
    private List<ProfileMenu> profileMenu;

    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 String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    @Transient
    public List<ProfileMenu> getProfileMenu() {
        return profileMenu;
    }

    public void setProfileMenu(List<ProfileMenu> profileMenu) {
        this.profileMenu = profileMenu;
    }

    @Override
    public String toString() {
        return "Menu [id=" + id + ", name=" + name + ", url=" + url + ", icon=" + icon + ", profileMenu=" + profileMenu
                + "]";
    }

}

这是将角色与菜单相关联的类

package com.escuelaapp.EscuelaApp.entity;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="profile_menu")
public class ProfileMenu {


    @Id
    @Column(name="id")
    private int id;
    @ManyToOne(targetEntity=Profile.class)
    @JoinColumn(name="profile_id")
    private Profile profileId;
    @ManyToOne(fetch=FetchType.EAGER,targetEntity=Menu.class)
    @JoinColumn(name="menu_id")
    private Menu menus;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

    public Profile getProfileId() {
        return profileId;
    }
    public void setProfileId(Profile profileId) {
        this.profileId = profileId;
    }
    public Menu getMenus() {
        return menus;
    }
    public void setMenus(Menu menus) {
        this.menus = menus;
    }
    @Override
    public String toString() {
        return "ProfileMenu [id=" + id + ", profileId=" + profileId + ", menus=" + menus + "]";
    }   
}

这是我的用户表与Spring Security的配置

package com.escuelaapp.EscuelaApp.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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 com.escuelaapp.EscuelaApp.entity.User;
import com.escuelaapp.EscuelaApp.repository.UserRepository;
@Service("UserServiceSecurity")
public class UserServiceSecurity implements UserDetailsService {
    @Autowired
    @Qualifier("UserRepository")
    private UserRepository userRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUserName(username);
        List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
        user.getProfile().getProfileMenus().stream().forEach((x) -> {
            auths.add(new SimpleGrantedAuthority(x.getMenus().getUrl()));
            //System.out.println(x.getMenus().getUrl());
        });
        return userBuiler(user, auths);
    }
    private org.springframework.security.core.userdetails.User userBuiler(User user,
            List<GrantedAuthority> authorities) {
        return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(),
                authorities);
    }
}

根据官方文档,这是通过http配置的Spring Security。

package com.escuelaapp.EscuelaApp.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("UserServiceSecurity")
    private UserDetailsService userService;

    @Autowired
    public void ConfigureGlobal(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
    }   

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
            .antMatchers("/inicio").permitAll()
            .antMatchers("/bower_components/**","/imgs/**","/css/**","/js/**","/fonts/**","/favicon.ico").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .permitAll()
            .loginPage("/inicio")           
            .failureUrl("/inicio?error")
            .loginProcessingUrl("/loginValidation")
            .usernameParameter("username")
            .passwordParameter("password")
            .defaultSuccessUrl("/dashboard")            
            .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/inicio?logout")
            .permitAll()
        ;       
    }

}

信息公开日:

select U.username, P.name, M.url from user U
join profile P on P.id=U.profile_id
join profile_menu  PM on PM.profile_id=P.id
join menu M on M.id=PM.menu_id

连结图片

最后,在控制器中,我具有以下路由,例如,我希望用户无权访问非管理员路由或任何未在数据库中注册的其他路由

package com.escuelaapp.EscuelaApp.controller;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.escuelaapp.EscuelaApp.configuration.EscuelappProperties;
import com.escuelaapp.EscuelaApp.entity.User;
import com.escuelaapp.EscuelaApp.model.CustomUserDetail;
import com.escuelaapp.EscuelaApp.model.LoggedUser;

@Controller
public class LoginController {

    private static final Log LOGGER = LogFactory.getLog(LoginController.class);

    @Autowired
    EscuelappProperties properties;  

    @GetMapping({"/inicio","/"})
    public String index(Model model,@RequestParam(required=false) String error, @RequestParam(required=false) String logout) {
        properties.initSliders();
        model.addAttribute("user", new User());
        model.addAttribute("prop", properties);
        model.addAttribute("error", error);
        model.addAttribute("logout", logout);
        return "index";
        //return "redirect:/login";
    }   


    @GetMapping("/dashboard")
    public ModelAndView dashboard() {
        ModelAndView mav = new ModelAndView("dashboard");
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
         //LoggedUser principal = (LoggedUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
         //CustomUserDetail principal = (CustomUserDetail) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
         //User user = principal.getUser();     
        //mav.addObject("user", user);
        mav.addObject("username", user.getUsername());
        return mav;
    }

    @GetMapping("/usuarios")
    public @ResponseBody String usuarios() {
        return "Tiene acceso a la ruta:  usuarios";
    }

    @GetMapping("/permisos")
    public @ResponseBody String permisos() {
        return "Tiene acceso a la ruta:  permisos";
    }   

    @GetMapping("/noAdministrador")
    public @ResponseBody String noAdmin() {
        return "Tiene acceso a la ruta:  no Admin";
    }   


}

感谢您与他们之间的合作,他们可以为我提供信息,以帮助他们了解Spring Security的工作方式,或者是否需要通过个人资料或角色进行权限验证,我必须手动进行。

为解决我的问题,我已将ROLE_ROLENAME设置为Authority as

@Service("UserServiceSecurity")
public class UserServiceSecurity implements UserDetailsService {

    @Autowired
    @Qualifier("UserRepository")
    private UserRepository userRepository;

    private String ROLE_PREFIX = "ROLE_";

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUserName(username);
        List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
        auths.add(new SimpleGrantedAuthority(ROLE_PREFIX+user.getProfile().getName()));
        user.getProfile().getProfileMenus().stream().forEach((x) -> {
            auths.add(new SimpleGrantedAuthority(x.getMenus().getUrl()));
        });
        return userBuiler(user, auths);
    }

    private org.springframework.security.core.userdetails.User userBuiler(User user,
            List<GrantedAuthority> authorities) {
        return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(),
                authorities);
    }
}

然后在Controller o方法中添加@PreAuthorize(“ hasRole('ROLENAME')”):

@Controller

@PreAuthorize("hasRole('DOCENTE')")
@RequestMapping("/docente")
public class TeacherController {

    //@PreAuthorize("hasAuthority('/docente/registrar-asistencia')")
    @GetMapping("/registrar-asistencia")
    public @ResponseBody String registrarAsistencia() {
        return "Tiene acceso a la ruta:  registrarAsistencia";
    }

    @GetMapping("/generar-boletin")
    public @ResponseBody String generarBoletin() {
        return "Tiene acceso a la ruta:  generar-boletin";
    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM