Apache Shiro 是一个功能强大且易于使用的Java安全框架,可进行身份验证,授权,加密和会话管理等。
在使用 shiro 之前, 我们先了解一下 shiro 权限管理的方式:
基于角色的访问控制
RBAC (Role-Based Access Control) ,
通过角色将用户和权限关联起来, 即一个用户可以拥有多个角色, 一个角色拥有多个权限.
所以先建立五张表:
// 管理员表
admin(id, username, password)
// 角色表
role(id, role_name)
// 权限表
permission(id, permission_name)
// 管理员-角色关联表
admin_role(id, admin_id, role_id)
// 角色-权限关联表
role_permission(id, role_id, permission_id)
实现相关的查询方法
public interface SysAdminService{
/**
* 这里是通过用户名直接将用户信息和其所有的角色和权限信息都查了出来, 然后封装在 AdminInfo 的对象中
* 具体实现就是根据用户名查用户, 然后根据用户 id 查角色, 再查权限, 最后封装, 如果用户不存在就直接返回 null
*/
AdminInfo getInfoByUsername(String username);
}
/**
* 用户身份信息类, 封装了其角色和权限
*/
public class AdminInfo implements Serializable {
private static final long serialVersionUID = 7899578061660728259L;
private Integer id;
private String username;
// 返回密码是为了进行身份认证
@JsonIgnore // 该注解是在将对象转化成 json 返回给前端的时候, 忽视该字段
private String password;
// 为了方便, 这里一个用户只对应一个角色
private String role;
private Integer roleId;
private Set<String> permissions;
/*
* 省略 get, set 方法
*/
}
然后就开始在SpringBoot 中搭建 shiro 了,
首先是引入依赖:
<!-- shiro 权限管理 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
定义 Realm
Realm 是 shiro 用来进行身份认证的获取角色权限信息的类, 我们通过继承 AuthorizingRealm
重写下面两个方法来获取用户的身份认证和权限信息.
public class ShiroRealm extends AuthorizingRealm {
@Autowired
private SysAdminService sysAdminService;
/**
* 根据 token 获取身份信息
* AuthenticationToken 是封装了登陆的 用户名和密码, 后面登陆的时候用到
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取用户名
String username = (String) token.getPrincipal();
AdminInfo admin = sysAdminService.getInfoByUsername(username);
// 用户不存在就直接返回 null 值
if (admin == null) {
return null;
}
/*
* 返回用户身份认证信息
* 构造方法为 SimpleAuthenticationInfo(Object principal, Object credentials, String realmName)
* 第一个参数是用户主体, 也可以存用户名
* 第二个参数用户凭据, 即密码
* 第三个就是 realm 的名字, 直接用 getName() 当前 realm
*/
return new SimpleAuthenticationInfo(admin, admin.getPassword(), getName());
}
/**
* 根据上面返回的身份信息获取授权信息
*
* @param principals
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 直接从用户主体信息中获取权限, 如果上面存用户名, 就还得在查一下权限
AdminInfo adminInfo = (AdminInfo) principals.getPrimaryPrincipal();
Set<String> permissions = adminInfo.getPermissions();
// 在授权信息中添加用户的角色和权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole(adminInfo.getRole());
info.setStringPermissions(permissions);
return info;
}
}
在 SpringBoot 中配置 Shiro
在这个 ShiroConfig 主要对 Shiro 的 realm, session, security, 过滤器等进行配置.
/**
* shiro 配置类
* springboot 会自动扫描该类中 @Bean 注解的对象, 并加载到spring容器中
*/
@Configuration
public class shiroConfig {
// 定义 shiro 的 cookie 的名字
private static String COOKIE_NAME = "shiro-session-cookie";
/**
* shiro 过滤器的配置
*/
@Bean
public ShiroFilterFactoryBean shiroFilter() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager()