智慧屏安装APP的最佳实践与跨平台小程序开发的结合
915
2022-11-29
Shiro:自定义Realm实现权限管理方式
目录Shiro权限管理1、基于javaSe的Shiro的基本使用1、导入shiro依赖2、创建shiro配置文件:shiro.ini3、shiro的基本使用4、shiro认证授权流程2、SpringBoot整合shiro1. 导入依赖2. 配置shiro过滤器3. 进行认证测试3、JdbcRealm实现权限管理1. JdbcRealm表结构2. 整合JdbcRealm4、实现前端的权限菜单展示1. 在Thymeleaf中使用标签2. 常用标签3. 认证流程回顾5、自定义Realm实现权限管理1. 表结构的设计2. Dao层实现3. 整合Shiro
Shiro权限管理
1、权限管理
权限管理:不同角色的用户进入到系统能够完成的操作是不同的,对不同角色的用户进行的可执行操作的管理称为权限管理。
2、如何实现权限管理
基于主页的权限管理:不同的用户使用不同的主页,权限通过主页功能菜单进行限制
基于用户权限的访问控制:统权限表、用户权限表、用户表,比较冗余
基于用户角色的访问控制(RBAC):系统权限表、用户权限表、用户表、角色表、用户角色表
1、基于JavaSe的Shiro的基本使用
1、导入shiro依赖
但是出现了一点问题:就是引入这个依赖后pom文件就会报错,可以在pom文件中加入加入阿里云的代理仓库:
2、创建shiro配置文件:shiro.ini
[users]
zhangsan=123456,seller
lisi=666666,ckmgr
admin=222222,admin
[roles]
admin=*
seller=order-add,order-del,order-list
ckmgr=ck-add,ck-del,ck-list
3、shiro的基本使用
public class TestShiro {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = sc.nextLine();
System.out.println("请输入密码:");
String password = sc.nextLine();
//创建安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//创建realm
IniRealm realm = new IniRealm("classpath:shiro.ini");
//将realm设置给安全管理器
securityManager.setRealm(realm);
//将realm设置给SecurityUtils工具
SecurityUtils.setSecurityManager(securityManager);
//通过SecurityUtils获取subject对象
Subject subject = SecurityUtils.getSubject();
//认证流程
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
System.out.println(subject.isAuthenticated());//false
//完成认证
subject.login(token);
System.out.println(subject.isAuthenticated());//true
//授权
//判断是否有某个角色
subject.hasRole("seller");//true
//判断是否有某个权限
boolean permitted = subject.isPermitted("oredr-del");
System.out.println(permitted);//true
}
}
4、shiro认证授权流程
(1) 通过subject.login(token)进行登录,就会将token包含的用户信息(账号和密码)传递给SecurityManager
(2) SecurityManGsXHJHuager会调用Authentication进行认证
(3) Authentication就会根据Realm安全信息进行认证校验
(4) Realm根据得到的token,调用doGetAuthenticationInfo()方法进行认证
(5) 认证完成后一层层返回到subject
2、SpringBoot整合shiro
1、导入shiro依赖:
2、配置shiro过滤器:拦截进行认证和授权的用户
3、配置SecurityManager到Spring容器
4、配置Realm(SecurityManager需要Realm)
1. 导入依赖
2. 配置shiro过滤器
/**
* Shiro的配置类
*/
@Configuration
public class ShiroConfig {
//将Realm交给Spring容器创建
@Bean
public IniRealm getRealm() {
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
return iniRealm;
}
//将DefaultSecurityManager交给Spring容器来创建和管理
@Bean
public DefaultSecurityManager getDefaultSecurityManager(IniRealm iniRealm) {
//SecurityManager要完成认证和校验需要Realm
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(iniRealm);
return securityManager;
}
//配置shiro的过滤器
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultSecurityManager securityManager) {
//过滤器工厂
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
//过滤器是进行权限校验的核心,进行认证和授权需要SecurityManager
filter.setSecurityManager(securityManager);
//设置拦截规则
//anon:匿名用户可以访问,authc:授权用户可以访问
Map
filterMap.put("/","anon"); //项目个根路径不拦截
filterMap.put("/login.html","anon"); //登录页面不拦截
filterMap.put("/register.html","anon"); //注册页面不拦截
filterMap.put("/user/login","anon"); //登录不拦截
filterMap.put("/user/regist","anon"); //注册不拦截
filterMap.put("/static/**","anon"); //静态页面不拦截
filterMap.put("/**","authc"); //除了上面的请求路径,其他路径都要拦截
filter.setFilterChainDefinitionMap(filterMap);
//设置默认的登录页面
filter.setLoginUrl("/login.html");
//设置未授权访问的页面路径(一个页面如果未授权让其跳转到登录页面)
filter.setUnauthorizedUrl("/login.html");
return filter;
}
}
3. 进行认证测试
1、UserService:
@Service
public class UserService {
public void check(String username,String password){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
subject.login(token);
}
}
2、UserController:
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/login")
public String login(String username,String password){
try {
userService.check(username,password);
System.out.println("登录成功");
return "index";
} catch (Exception e) {
System.out.println("登录失败");
return "login";
}
}
}
3、login.html登录页面:
用户名:
密码:
4、shiro.ini配置文件:
[users]
zhangsan=123456
5、认证成功:跳到index首页
6、认证失败,跳到登录页面
3、JdbcRealm实现权限管理
1. JdbcRealm表结构
这些表名和表结构都是固定的不能更改:
用户信息表:users
create table users(
id int primary key auto_increment,
username varchar(60) not null unique,
password varchar(20) not null,
password_salt varchar(20)
)
insert into users(username,password) values("zhangsan","123456");
insert into users(username,password) values("lisi","123456");
insert into users(username,password) values("wangwu","123456");
insert into users(username,password) values("zhaoliu","123456");
insert into users(username,password) values("chenqi","123456");
角色信息表:user_roles
create table user_roles(
id int primary key auto_increment,
username varchar(60) not null,
role_name varchar(100) not null
)
insert into user_roles(username,role_name) values("zhangsan","admin");
insert into user_roles(username,role_name) values("lisi","cmanager"); -- 库管人员
insert into user_roles(username,role_name) values("wangwu","xmanager");-- 销售人员
insert into user_roles(username,role_name) values("zhaoliu","kmanager");-- 客服人员
insert into user_roles(username,role_name) values("chenqi","zmanager"); -- 行政人员
权限信息表:roles_permissions
create table roles_permissions(
id int primary key auto_increment,
role_name varchar(60) not null,
permission varchar(100) not null
)
-- 管理员具备所有权限
insert into roles_permissions(role_name,permission) values("admin","*");
-- 库管人员
insert into roles_permissions(role_name,permission) values("cmanager","sys:c:save");
insert into roles_permissions(role_name,permission) values("cmanager","sys:c:delete");
insert into roles_permissions(role_name,permission) values("cmanager","sys:c:find");
insert into roles_permissions(role_name,permission) values("cmanager","sys:c:update");
-- 销售人员
insert into roles_permissions(role_name,permission) values("xmanager","sys:c:save");
insert into roles_permissions(role_name,permission) values("xmanager","sys:x:find");
insert into roles_permissions(role_name,permission) values("xmanager","sys:x:delete");
insert into roles_permissions(role_name,permission) values("xmanager","sys:x:update");
insert into roles_permissions(role_name,permission) values("xmanager","sys:k:save");
insert into roles_permissions(role_name,permission) values("xmanager","sys:k:find");
insert into roles_permissions(role_name,permission) values("xmanager","sys:k:delete");
insert into roles_permissions(role_name,permission) values("xmanager","sys:k:update");
-- 客服人员
insert into roles_permissions(role_name,permission) values("kmanager","sys:k:find");
insert into roles_permissions(role_name,permission) values("kmanager","sys:k:update");
-- 行政人员
insert into roles_permissions(role_name,permission) values("zmanager","sys:k:find");
2. 整合JdbcRealm
1、整合Druid和MyBatis:
# 数据库配置
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/db_shiro1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.druid.username=root
spring.datasource.druid.password=root
# 连接池配置
#连接池建立时创建的初始化连接数
spring.datasource.druid.initial-size=5
#连接池中最大的活跃连接数
spring.datasource.druid.max-active=20
#连接池中最小的活跃连接数
spring.datasource.druid.min-idle=5
# 配置获取连接等待超时的时间
spring.datasource.druid.max-wait=60000
# mybatis 配置
mybatis.mapper-locations=classpath:mappers/*Mapper.xml
mybatis.type-aliases-package=com.hh.beans
2、导入shiro依赖:
3、配置shiro过滤器:只需要将IniRealm 更改为JdbcRealm
@Configuration
public class ShiroConfig {
@Bean
public JdbcRealm getJDBCRealm(DataSource dataSource){
JdbcRealm jdbcRealm = new JdbcRealm();
//JdbcRealm会自行从数据库中查询用户和权限数据(前提是数据库表结构要符合JdbcRealm表结构)
jdbcRealm.setDataSource(dataSource);
//jdbcRealm默认开启认证功能,如果想要开启授权功能,需要手动开启
jdbcRealm.setPermissionsLookupEnabled(true);
return jdbcRealm;
}
//将DefaultSecurityManager交给Spring容器来创建和管理
@Bean
public DefaultSecurityManager getDefaultSecurityManager(JdbcRealm jdbcRealm) {
//SecurityManager要完成认证和校验需要Realm
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(jdbcRealm);
return securityManager;
}
//配置shiro的过滤器
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultSecurityManager securityManager) {
//过滤器工厂
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
//过滤器是进行权限校验的核心,进行认证和授权需要SecurityManager
filter.setSecurityManager(securityManager);
//设置拦截规则
//anon:匿名用户可以访问,authc:授权用户可以访问
Map
filterMap.put("/", "anon"); //项目个根路径不拦截
filterMap.put("/login.html", "anon"); //登录页面不拦截
filterMap.put("/register.html", "anon"); //注册页面不拦截
filterMap.put("/user/login", "anon"); //登录不拦截
filterMap.put("/user/regist", "anon"); //注册不拦截
filterMap.put("/static/**", "anon"); //静态页面不拦截
filterMap.put("/**", "authc"); //除了上面的请求路径,其他路径都要拦截
filter.setFilterChainDefinitionMap(filterMap);
//设置默认的登录页面
filter.setLoginUrl("/login.html");
//设置未授权访问的页面路径(一个页面如果未授权让其跳转到登录页面)
filter.setUnauthorizedUrl("/login.html");
return filter;
}
}
4、进行认证测试:和上面测试方法相同
由于只要我们按照规定写了数据库表结构,那么既可以直接使用数据库中的信息
4、实现前端的权限菜单展示
1. 在Thymeleaf中使用标签
1、在pom.xml文件中导入thymeleaf模版对shiro标签支持的依赖
2、在ShiroConfig中配置Shiro的方言:
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
3、Thymeleaf模版中引入shiro的命名空间:
xmlns:shiro="http://pollix.at/thymeleaf/shiro">
...
2. 常用标签
2.1 guest
判断用户是否是游客身份,如果是游客身份则显示此标签内容
欢迎游客,请登录
2.2 user
判断用户是否是认证身份,如果是认证身份则显示此标签内容
已登录用户
2.3 principal
获取当前登录用户名
已登录用户
2.4 hasRole
当期那登录用户的角色
当前用户
当前用户为
登录用户为zhangsan:
登录用户为lisi:
2.5 hasPermission
当前登录用户具有的权限
xmlns:shiro="http://pollix.at/thymeleaf/shiro">
欢迎游客,请登录
当前用户
当前用户为
仓库管理:
订单管理:
客户管理:
登录用户为:lisi
登录用户为zhangsan:
3. 认证流程回顾
5、自定义Realm实现权限管理
1. 表结构的设计
1.1 用户表:tb_users
create table tb_users(
user_id int primary key auto_increment,
username varchar(60) not null unique,
password varchar(20) not null,
password_salt varchar(60)
);
insert into tb_users(username,password) values("zhangsan","123456");
insert into tb_users(username,password) values("lisi","123456");
insert into tb_users(username,password) values("wangwu","123456");
insert into tb_users(username,password) values("zhaoliu","123456");
insert into tb_users(username,password) values("chenqi","123456");
1.2 角色表:tb_roles
create table tb_roles(
role_id int primary key auto_increment,
role_name varchar(100) not null
);
insert into tb_roles(role_name) values("admin");
insert into tb_roles(role_name) values("cmanager");
insert into tb_roles(role_name) values("xmanager");
insert into tb_roles(role_name) values("kmanager");
insert into tb_roles(role_name) values("zmanager");
1.3 权限表:tb_permissions
create table tb_permissions(
permission_id int primary key auto_increment,
permission_code varchar(20) not null,
permission_name varchar(60)
);
insert into tb_permissions(permission_code,permission_name) values("sys:c:save","入库");
insert into tb_permissions(permission_code,permission_name) values("sys:c:delete","出库");
insert into tb_permissions(permission_code,permission_name) values("sys:c:update","修改");
insert into tb_permissions(permission_code,permission_name) values("sys:c:find","查询");
insert into tb_permissions(permission_code,permission_name) values("sys:x:save","新增订单");
insert into tb_permissions(permission_code,permission_name) values("sys:x:delete","删除订单");
insert into tb_permissions(permission_code,permission_name) values("sys:x:update","修改订单");
insert into tb_permissions(permission_code,permission_name) values("sys:x:find","查询订单");
insert into tb_permissions(permission_code,permission_name) values("sys:k:save","新增客户");
insert into tb_permissions(permission_code,permission_name) values("sys:k:delete","删除客户");
insert into tb_permissions(permission_code,permission_name) values("sys:k:update","修改客户");
insert into tb_permissions(permission_code,permission_name) values("sys:k:find","查询客户");
1.4 用户角色表:tb_urs
create table tb_urs(
uid int not null,
rid int not null
-- primary key(uid,rid),
-- constraint FK_user foreign key(uid) references tb_users(user_id),
-- constraint FK_role foreign key(rid) references tb_rolls(roll_id)
);
-- zhangsan具有所有角色,代表具有所有权限,不用给他分配权限
insert into tb_urs(uid,rid) values(1,1);-- zhangsan用户具有admin角色
insert into tb_urs(uid,rid) values(1,2);-- zhangsan用户具有cmanager角色
insert into tb_urs(uid,rid) values(1,3);-- zhangsan用户具有xmanager角色
insert into tb_urs(uid,rid) values(1,4);-- zhangsan用户具有kmanagerr角色
insert into tb_urs(uid,rid) values(1,5);-- zhangsan用户具有zmanager角色
insert into tb_urs(uid,rid) values(2,2);-- lisi用户具有cmanager角色
insert into tb_urs(uid,rid) values(3,3);-- wangwu用户具有xmanager角色
insert into tb_urs(uid,rid) values(4,4);-- zhaoliu用户具有kmanager角色
insert into tb_urs(uid,rid) values(5,5);-- chenqi用户具有zmanager角色
1.5 角色权限表:tb_rps
create table tb_rps(
rid int not null,
pid int not null
);
-- 给角色2(仓管)分配权限
insert into tb_rps(rid,pid) values(2,1);
insert into tb_rps(rid,pid) values(2,2);
insert into tb_rps(rid,pid) values(2,3);
insert into tb_rps(rid,pid) values(2,4);
-- 给角色3(销售)分配权限
insert into tb_rps(rid,pid) values(3,3);
insert into tb_rps(rid,pid) values(3,5);
insert into tb_rps(rid,pid) values(3,6);
insert into tb_rps(rid,pid) values(3,7);
insert into tb_rps(rid,pid) values(3,8);
insert into tb_rps(rid,pid) values(3,9);
insert into tb_rps(rid,pid) values(3,10);
insert into tb_rps(rid,pid) values(3,11);
insert into tb_rps(rid,pid) values(3,12);
-- 给角色4(客服)分配权限
insert into tb_rps(rid,pid) values(4,11);
insert into tb_rps(rid,pid) values(4,12);
-- 给角色5(行政)分配权限
insert into tb_rps(rid,pid) values(5,4);
insert into tb_rps(rid,pid) values(5,8);
insert into tb_rps(rid,pid) values(5,12);
2. Dao层实现
shiro 进行认证需要用户信息:
根据用户名查询用户信息
shiro进行权限管理需要当前用户的角色和权限:
根据用户名查询当前用户的角色列表
根据用户名查询当前用户的权限列表
2.1 根据用户名查询用户信息
实体类User
@Data
public class User {
private String userId;
private String userName;
private String userPwd;
private String pwdSalt;
}
dao接口
@Mapper
public interface UserDao {
//根据用户名查询用户信息
public User queryUserByUsername(String username) throws Exception;
}
映射配置
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
select * from tb_users
where username=#{username}
2.2 根据用户名查询角色信息
dao接口
@Mapper
public interface RoleDao {
public Set
}
映射配置
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
select
role_name
from
tb_users
join
tb_urs
on
tb_users.user_id = tb_urs.uid
join
tb_roles
on
tb_urs.rid = tb_roles.role_id
where
tb_users.username=#{username}
2.3 根据用户名查询权限列表
dao接口
public interface PermissionDAO {
public Set
}
映射配置
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
select
tb_permissions.permission_code
from
tb_users
join
tb_urs
on
tb_users.user_id=tb_urs.uid
join
tb_roles
on
tb_urs.rid=tb_roles.role_id
join
tb_rps
on
tb_roles.role_id=tb_rps.rid
join
tb_permissions
on
tb_rps.pid=tb_permissions.permission_id
where
tb_users.username=#{username}
3. 整合Shiro
3.1 导入依赖
3.2 配置Shiro过滤器
@Configuration
public class ShiroConfig {
//1、配置Shiro的方言支持
//2、配置Realm
//3、配置SecurityManager
//4、配置过滤器
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
//自定义Realm,Realm相当于数据源,从数据库中查询出认证信息和授权信息
@Bean
public MyRealm getRealm(){
MyRealm myRealm = new MyRealm();
return myRealm;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
//过滤器就是shiro就行权限校验的核心,进行认证和授权是需要SecurityManager的
filter.setSecurityManager(securityManager);
Map
filterMap.put("/","anon");
filterMap.put("/index.html","anon");
filterMap.put("/login.html","anon");
filterMap.put("/regist.html","anon");
filterMap.put("/user/login","anon");
filterMap.put("/user/regist","anon");
filterMap.put("/layui/**","anon");
filterMap.put("/**","authc");
filter.setFilterChainDefinitionMap(filterMap);
filter.setLoginUrl("/login.html");
//设置未授权访问的页面路径()
filter.setUnauthorizedUrl("/login.html");
return filter;
}
}
3.3 自定义Realm
/**
* 自定义Realm的规范:
* 1、创建一个类实现AuthorizingRealm,重写里面的两个方法
* 2、重写getName()方法,返回当前Realm的自定义名称
*/
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserDao userDao;
@Autowired
private RoleDao roleDao;
@Autowired
private PermissionDao permissionDao;
public String getName(){
return "myRealm";
}
/**
* 获取认证信息:将用户密码查询出来交给shiro
* @param authenticationToken token就是传递的 subject.login(token)
*/
@SneakyThrows
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//从token中获取用户名
String username = token.getUsername();
//根据用户名到数据库中查询用户信息
User user = userDao.queryUserByUsername(username);
if(user==null){
return null;
}
//将查询出来的密码封装成安全信息给shiro
AuthenticationInfo info = new SimpleAuthenticationInfo(
username,//当前用户的用户名
user.getUserPwd(),//从数据库中查询出来的安全数据
getName()
);
return info;
}
/**
* 获取授权信息:将当前用户的角色和权限查询出交给shiro
* @param principalCollection
*/
@SneakyThrows
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户的用户名
String username = (String)principalCollection.iterator().next();
//根据用户名查询用户的角色列表
Set
//根据用户名查询用户的权限列表
Set
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roleNames);
info.setStringPermissions(ps);
return info;
}
}
测试结果:
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~