《Spring Boot 实战派》--14.开发企业级通用的后台系统
第14章 开发企业级通用的后台系统
使用Spring Boot,免不了开发后台系统。所以,本章通过实现一个基于角色的访问控制后台 系统,来系统地介绍如何使用Spring Security。
本实例的源代码可以在“/14/ManagementSystemDemo”目录下找到。
14.1用JPA实现实体间的映射关系
RBAC ( Role Based Access Control)是基于角色的访问控制,一般分为用户(user)、角 色(role)、权限(permission ) 3个实体。它们的关系如下:
- 角色(role)和权限(permission )是多对多关系。
- 用户(user)和角色(role)也是多对多的关系。
- 用户(user)和权限(permission )之间没有直接的关系。用户需要通过角色作为代理(中 间人)来获取到拥有的权限。
5 张表就能实现角色、用户、权限的映射关系,其中包含3个实体表和2个关系表(角色一权 限关系表、用户一角色关系表)。
14.1.1创建用户实体
用户实体类通过实现UserDetaiis接口实现认证及授权,见以下代码:
package com.example.demo.entity.sysuser; ?Entity public class SysUser implements UserDetails (
//主键及自动增长 @ld @GeneratedValue private long id;
@Column(nullable = false, unique = true) private String name; private String password; private String cnname; private Boolean enabled = Boolean.TRUE; /** * 多对多映用户角色 */ @ManyToMany(cascade = (CascadeType.REFRESH), fetch = FetchType.EAGER)
private Listroles; public long getld() { return id; }
/**
* 根据自定义逻辑来返回用户权限。如果用户权限返回空,或者和拦截路径对应权限不同,则验证不通过 */ @Override public Collection<? extends GrantedAuthority> getAuthorities() { Listauthorities = new ArrayList<>(); List roles = this.getRoles(); for (SysRole role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getRole())); } return authorities; } }
14.1.2创建角色实体
角色是用户和权限的中间代理表。用户(user)和权限(permission )之间没有直接的关系, 用户(user)需要通过角色作为代理(中间人)来获取拥有的权限,见以下代码:
@Data
@Entity
public class SysRole {
@ld
@GeneratedValue
/**
* 编号
*/
private Integer id;
private String cnname;
/**
* 角色标识,如“管理员”
*/
private String role;
/**
* 角色描述,用于在Ul界面显示角色信息
*/
private String description;
/**
* 是否可用。如果不可用,则不会添加给用户
*/
private Boolean available = Boolean.FALSE;
/**
* 角色一权限关系:多对多关系
*/
@ManyToMany(fetch = FetchType. EAGER)
@JoinTable(name = "SysRolePermission", joinColumns = (@JoinColumn(name ="roleld")), inverseJoinColumns = {@JoinColumn(name = "permissionld")))
private List permissions;
/**
* 用户一角色关系:多对多关系
*/
@ManyToMany
@JoinTable(name = "SysUserRole", joinColumns = (@JoinColumn(name = "roleld")), inverseJoinColumns = (@JoinColumn(name = "uid")))
/**
* —个角色对应多个用户
*/
private List userinfos;
)
14.1.3创建权限实体
权限和角色存在多对多关系。一般情况下,权限不会和用户直接关联,它用于存放权限信息, 比如权限的名称、HTTP方法、URL路径。具体见以下代码:
@Data
?Entity
public class SysPermission implements Serializable {
@ld
@GeneratedValue
/**
* 主键
*/
private Integer id;
/**
* 名称
*/
private String name;
@Column(columnDefinition = "enumCmenu','button')")
/**
* 资源类型,[menu|button]
*/
private String resourceType;
/**
* 资源路径
*/
private String url;
/**
* 权限字符串。menu
* 例子:role:*; button 例子:role:create,role:update,role:delete,role:view
*/
private String permission;
/**
*父编号
*/
private Long parentld;
/**
* 父编号列表
*/
private String parentlds;
private Boolean available = Boolean.FALSE;
?Transient
private List permissions;
@ManyToMany
@JoinTable(name = "SysRolePermission", joinColumns = {@JoinColumn(name = "permissionld")), inverseJoinColumns = {@JoinColumn(name = "roleld")))
private List roles;
public List getPermissionsO (
return Arrays.asList(this.permission.trimO.split('T'));
}
public void setPermissions(List permissions) {
this.permissions = permissions;
}
}
14.2用Spring Security实现动态授权(RBAC)功能
14.2.1实现管理(增加、删除、修改和查询)管理员角色功能
1、实现控制器
控制器主要指定URL映射和视图,见以下代码:
?Controller
@RequestMapping("admin")
public class SysRoleControlller {
@Autowired
private SysRoleRepository sysRoleRepository;
@RequestMapping("/role/add")
public String addRole() {
return "admin/role/add";
}
@RequestMapping("/role")
public String addRole(SysRole model) {
String role = "ROLE_" + model.getRole();
model.setRole(role);
sysRoleRepository.save(model);
return "redirect:/admin/";
}
)
2、视图页面
这里注意,要提交CSRF的token (根据需求可以不幵启CSFR), token的值需要在HTML 中的head标签中添加。见下面代码注释标签之间的部分,以及在表单(form ) 中的隐臓提交CSRF的token值。
〈input type="submit" value=”提交"class="btn btn-info" />
14.2.2实现管理权限功能
1.实现权限控制器
权限管理主要是对权限迸行增加、删除' 修改和查询操作。权限要和角色对应起来。在进行操 作时需要附带角色字段,见以下代码:
?Controller
@RequestMapping(7admin/permission")
public class SysPermissionControler {
@Autowired
private SysPermissionRepository sysPermissionRepository;
@Autowired
private SysRoleRepository sysRoleRepository;
@RequestMapping("/add")
public String addPermission(Model model) {
List sysRole = sysRoleRepository.findAII();
model.addAttribute("sysRole", sysRole);
return "admin/permission/add";
}
@PostMapping("/add")
public String addPermission(SysPermission sysPermission, String role) (
List roles = new ArrayList<>();
SysRole rolel = sysRoleRepository.findByRole(role);
roles.add(rolel);
sysPermission.setRoles(roles);
sysPermissionRepository.save(sysPermission);
return "redirect:/admin/";
}
}
2.实现视图模板
在以下代码中,视图中的$(sysRole)是根据控制器返回的参数;“th:each”标签是Thymeleaf 的标签,用于遍历数据。
14.2.3实现管理管理员功能
管理员密码是需要加密的,这里采用“BCrypt”方式加密。如果读者用自己喜欢的加密方式, 则需要新建加密工具类,同时要在安全配置类重写加密配置方式。
1.实现控制器
主要注意密码加密■'BCryptPasswordEncoder"和角色遍历部分,见以下代码:
@Autowired private SysUserRepository adminUserRepository;
@Autowired private SysRoleRepository sysRoleRepository;
//@PreAuthorize("hasRole('ROLE_admin')") @RequestMapping(7user/add") public String toAddUser(Model model) ( Listadminrole = sysRoleRepository.findAII(); model.addAttribute("adminrole", adminrole); return "admin/user/add"; }
//@RequestMapping('7user/add") @PostMapping(*7user") public String addUser(String name, String password, String role) { BCryptPasswordEncoder encoder = new BCryptPasswordEncoderO; String encodePassword 二 encoder.encode(password); SysUser user = new SysUser(name, encodePassword); Listroles = new ArrayList<>(); SysRole rolel = sysRoleRepository.findByRole(role); roles.add(rolel); user,setRoles(roles); adminUserRepository.save(user); return "redirect:/admin/"; }
2.视图页面
在视图页面中请注意遍历ll${adminrole}"这个用户角色,见以下代码: