我有一个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
+ "]";
}
}
这是将ROLE与菜单相关的类
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的工作方式,或者是否需要通过配置文件或角色进行权限验证。
答案 0 :(得分:0)
为解决我的问题,我已将ROLE_ROLENAME设置为Authority为
@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";
}
}