Предоставлять или ограничивать разрешения для маршрутов через роли в Spring Security в Spring Boot - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть приложение Spring, в котором я реализовал Boot Spring Security. Мне удалось войти в систему и получить доступ ко всем маршрутам после входа в систему, а также ограничения для всех маршрутов, когда сеанс не был запущен. В моей системе у меня есть список Users -> Roles -> 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);
    }
}

Это конфигурация Spring Security по http, согласно официальной документации

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, или если для проверки прав доступа по профилям или ролям я должен сделать это вручную.

1 Ответ

0 голосов
/ 09 ноября 2018

Чтобы исправить мою проблему, я установил ROLE_ROLENAME в качестве Полномочия как

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

И затем добавьте @PreAuthorize ("hasRole ('ROLENAME')") в метод Controller o:

@ Контроллер

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

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...