步骤一
在pom.xml
中添加shiro
的依赖:
org.apache.shiro
shiro-spring
1.4.0
步骤二
建立相关数据表:用户表、用户-角色表、角色表、角色-权限表,权限表。由于不同的项目表中的数据项不同所以下面仅列出较为重要的属性,其他的属性可根据实际需求自行添加。(这里采用的是Hibernate
注解方式自动建表)
- 用户表:
@Entity
@Table(name = "tb_admin")
public class Admin {
/**
* 用户名/工号
*
* 长度为9
* 示例 201904001
*/
@Id
@Column(length = 9)
private String username;
/**
* 密码
*/
@Column(nullable = false, length = 20)
private String password;
/**
* 角色列表
*
* 一个用户可以有多个角色
*/
@ManyToMany(fetch = FetchType.EAGER) //立即从数据库中加载数据
@JoinTable(name = "tb_admin_role", joinColumns = {@JoinColumn(name = "username")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
private List roleList;
public Admin() {
}
//省略get set方法
}
- 角色表:
@Entity
@Table(name = "tb_role")
public class Role {
/**
* roleId
*
* 自增序列
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int roleId;
/**
* 角色字符串
*
* 用于角色控制
* 不能为空
*/
@Column(length = 50, nullable = false)
private String role;
// 用户 - 角色关系定义;
@ManyToMany
@JoinTable(name = "tb_admin_role", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "username")})
private List adminList;// 一个角色对应多个用户
// 角色 - 权限关系定义;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "tb_role_permission", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "permissionId")})
private List permissionList;// 一个角色有多个权限
public Role() {
}
//省略get set方法
}
- 权限表:
@Entity
@Table(name = "tb_permission")
public class Permission {
/**
* permissionId
*
* 自增序列
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int permissionId;
/**
* 权限字符串
*
* 用于权限控制
* 不能为空
*/
@Column(length = 50, nullable = false)
private String permission;
// 角色 - 权限关系定义;
@ManyToMany
@JoinTable(name = "tb_role_permission", joinColumns = {@JoinColumn(name = "permissionId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
private List roleList;// 一个角色有多个权限
public Permission() {
}
//省略get set方法
}
- 用户-角色表:
@Entity
@Table(name = "tb_admin_role")
public class AdminRole {
/**
* id
*
* 自增序列
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
/**
* 管理员Id
*/
@Column(nullable = false,length = 9)
private String username;
/**
* 角色id
*/
@Column(nullable = false)
private int roleId;
public AdminRole() {
}
//省略get set方法
}
- 角色-权限表:
@Entity
@Table(name = "tb_role_permission")
public class RolePermission {
/**
* id
*
* 自增序列
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
/**
* 角色Id
*/
@Column(nullable = false)
private int roleId;
/**
* 权限id
*/
@Column(nullable = false)
private int permissionId;
public RolePermission() {
}
//省略get set方法
}
至此,环境搭好了,相关数据表也建好了,接下来只需要通过shiro
进行关联配置即可。
步骤三
新建ShiroConfig
配置文件:
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
* 用户主体 把操作交给SecurityManager
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/*
Shiro内置过滤器,可以实现权限相关的拦截器
常用的过滤器:
anon: 无需认证(登录)可以访问
authc: 必须认证才可以访问
user: 如果使用rememberMe的功能可以直接访问
perms: 该资源必须得到资源权限才可以访问
role: 该资源必须得到角色权限才可以访问
*/
Map filterMap = new LinkedHashMap<>();
//放行
filterMap.put("/test", "anon");
filterMap.put("/login", "anon");
//授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权页面
filterMap.put("/testSelect", "perms[selectTest]");
filterMap.put("/testAdd", "perms[addTest]");
//必须认证(登录)
filterMap.put("/*", "authc");
//未登录状态访问其他url
shiroFilterFactoryBean.setLoginUrl("/needLogin");
//设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
* 安全管理器 关联Realm
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 创建Realm
* 连接数据的桥梁
*/
@Bean(name = "userRealm")
public UserRealm getRealm() {
return new UserRealm();
}
}
其中需要注意的是,通过filterMap
设置指定url
的访问权限或角色,如filterMap.put("/testSelect", "perms[selectTest]");
这条语句的意思就是访问/testSelect
需要selectTest
权限才能访问。
其次,要登录之后才会被授权,授权后才能访问相应权限的url
,否则会跳转到shiroFilterFactoryBean.setLoginUrl("/needLogin");
这句话所指定的url地址。
步骤四
创建UserRealm
文件:
public class UserRealm extends AuthorizingRealm {
@Autowired
AdminRepository adminRepository;
/**
* 执行授权逻辑
* 登录时授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权逻辑");
//给资源进行授权
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
Admin admin = (Admin) principals.getPrimaryPrincipal();
for (Role role : admin.getRoleList()) {
//添加角色
authorizationInfo.addRole(role.getRole());
for (Permission permission : role.getPermissionList()) {
//添加权限
authorizationInfo.addStringPermission(permission.getPermission());
}
}
return authorizationInfo;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
//编写shiro判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
Admin admin = adminRepository.findByUsername(token.getUsername());
if (admin == null) {
//用户名不存在
return null; //UnknownAccountException
}
//判断密码
return new SimpleAuthenticationInfo(admin, admin.getPassword(), "");
}
}
步骤五
至此,Shiro
的权限控制就完成了,现在只需在数据表中添加相应数据项即可。最后,附上上述代码中所涉及到的url
接口:
/**
* 登录
*
* @param username 用户名
* @param password 密码
* @return Msg
*/
@PostMapping("/login")
public Msg Login(@RequestParam("username") String username,
@RequestParam("password") String password) {
/*
使用Shiro编写认证操作
*/
//1.获取Subject
Subject subject = SecurityUtils.getSubject();
//2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//3.执行登录方法
try {
//将跳转到UserRealm中去
subject.login(token);
} catch (UnknownAccountException e) {
e.printStackTrace();
//登录失败
return new Msg(ResultCode.RESULT_CODE_USER_NOT_EXIST);
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
//密码错误
return new Msg(ResultCode.RESULT_CODE_ERROR_PASSWORD);
}
return new Msg("登录成功");
}
/**
* 未登录就请求其他url
*/
@RequestMapping("/needLogin")
public Msg needLogin() {
return new Msg(ResultCode.RESULT_CODE_NEED_LOGIN);
}
/**
* 未授权
*/
@RequestMapping("/noAuth")
public Msg noAuth() {
return new Msg(ResultCode.RESULT_CODE_NO_PERMISSION);
}
@RequestMapping("/testSelect")
public String testSelect() {
return "testSelect";
}
@RequestMapping("/testAdd")
public String testAdd() {
return "testAdd";
}
参考资源: springboot(十四):springboot整合shiro-登录认证和权限管理,SpringBoot与Shiro整合-权限管理实战视频