一、数据库模板设计
在本文中,我们使用RBAC(Role-Based Access Control,基于角色的访问控制)模型设计用户,角色和权限间的关系。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系
一个用户对应一个或者多个角色。
一个角色对应一个或者多个权限。
一个权限对应能够访问对应的API或url资源。
1 . RBAC基本实体关系,Permission类(权限资源) :
/**
* Created by EalenXie on 2019/3/25 11:15.
* <p>
* 权限许可(Permission) 操作 及其能访问url 权限对应一个url地址
*/
@Entity
@Table(name = "system_shiro_permission")
public class Permission extends BaseEntity {
@Column(unique = true)
private String name; //权限名 唯一
@Column(unique = true)
private String url; //访问地址信息 唯一
private String description; //描述信息
//省略getter/setter
}
2 . Role类(用户角色),一个角色拥有一个或者多个权限 :
/**
* Created by EalenXie on 2019/3/25 11:18.
* <p>
* 角色(Role) 角色下面对应多个权限
*/
@Entity
@Table(name = "system_shiro_role")
public class Role extends BaseEntity {
@Column(unique = true)
private String name; //角色名 唯一
private String description; //描述信息
@ManyToMany(fetch= FetchType.EAGER)
private List<Permission> permissions; //一个用户角色对应多个权限
//省略getter/setter
}
3 . User类(用户),一个用户拥有一个或者多个角色 :
/**
* Created by EalenXie on 2019/3/25 11:01.
* <p>
* 用户表(User) 用户下面对应多个角色
*/
@Entity
@Table(name = "system_shiro_user")
public class User extends BaseEntity {
@Column(unique = true)
private String username;//用户名 唯一
private String password;//用户密码
private String passwordSalt;//用户密码加密盐值
@ManyToMany(fetch = FetchType.EAGER)
private List<Role> roles;//用户角色 一个用户可能有一个角色,也可能有 多个角色
//省略getter/setter
}
以上是对应关系的实体,数据库字段根据上述实体创建,这里就不写出来了。设计到的查询根据实际情况自己写,这里主要是讲shiro
二:Shiro整合实现思路
我们先来屡一下思路,实现认证权限功能主要可以归纳为3点:
1.定义一个ShiroConfig配置类,配置 SecurityManager Bean , SecurityManager为Shiro的安全管理器,管理着所有Subject;
2.在ShiroConfig中配置 ShiroFilterFactoryBean ,它是Shiro过滤器工厂类,依赖SecurityManager ;
3.自定义Realm实现类,包含
doGetAuthorizationInfo()
和doGetAuthenticationInfo()
方法
下面我们就来实现这些步骤:
1、定义ShiroConfig配置类
/**
* Shiro配置
*/
@Configuration
public class ShiroConfig {
@Resource
private OAuth3Realm userAuthRealm;
/**
* 配置安全管理器
* @param oAuth3Realm UserRealm
* @return DefaultWebSecurityManager
*/
@Bean
public SecurityManager securityManager(OAuth3Realm oAuth3Realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(oAuth3Realm);
return securityManager;
}
/**
* 配置Shiro过滤器工厂
* 配置 资源访问策略 . web应用程序 shiro核心过滤器配置
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager, UrlConfig urlConfig) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 注册安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 定义资源访问规则
Map<String, String> filterMap = new LinkedHashMap<String, String>(16);
/*
* 过滤器说明
* anon:不需要认证就可以访问的资源
* authc:需要登录认证才能访问的资源
* perms:需要指定权限才能访问的资源
*/
// 需要登录认证才能访问的资源
//oauth过滤,anon:不需要认证就可以访问的资源
Map<String, Filter> filters = new LinkedHashMap<>();
filters.put("oauth3", new OAuth3Filter());
// TODO 增加新的B端用户拦截器
shiroFilterFactoryBean.setFilters(filters);
//排除配置
if (urlConfig.getAnonUrl() != null && !urlConfig.getAnonUrl().isEmpty()) {
for (String anonUrl : urlConfig.getAnonUrl()) {
filterMap.put(anonUrl, "anon");
}
}
//对所有用户认证 对B端访问路由进行拦截
filterMap.put("/**", "oauth3");
//配置 拦截过滤器链
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 开启shiro 注解支持. 使以下注解能够生效 :
* 需要认证 {@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}
* 需要用户 {@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}
* 需要访客 {@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}
* 需要角色 {@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles}
* 需要权限 {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions}
* 启用shiro注解
*加入注解的使用,不加入这个注解不生效
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(secu