一、Shiro认证流程回顾
subject调用login方法,将包含用户和密码token传递给SecurityManager
SecurityManager就会调用认证器(Authenticator)进行认证
Authenticator认证器将token传入绑定的Realm,在Realm中进行认证检查;如果认证通过正常执行,认证失败不通过抛出异常。
自定义MyRealm
1.1表设计
用户表 | tb_users |
角色表 | tb_roles |
权限表 | tb_permissions |
用户角色表 | tb_urs |
角色权限表 | tb_rps |
- RBAC基于角色的访问控制
```sql
-- 用户信息表
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');
-- 角色信息表
create table tb_roles(
role_id int primary key auto_increment,
role_name varchar(60) 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'); -- 行政
-- 权限信息表
create table tb_permissions(
permission_id int primary key auto_increment, -- 1
permission_code varchar(60) not null, -- sys:c:find
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','查询客户');
-- 用户角色表
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_roles(role_id)
);
insert into tb_urs(uid,rid) values(1,1);
insert into tb_urs(uid,rid) values(1,2);
insert into tb_urs(uid,rid) values(1,3);
insert into tb_urs(uid,rid) values(1,4);
insert into tb_urs(uid,rid) values(1,5);
insert into tb_urs(uid,rid) values(2,2);
insert into tb_urs(uid,rid) values(3,3);
insert into tb_urs(uid,rid) values(4,4);
insert into tb_urs(uid,rid) values(5,5);
-- 角色权限表
create table tb_rps(
rid int not null,
pid int not null
);
-- 给仓管角色分配权限
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);
-- 给销售角色分配权限
insert into tb_rps(rid,pid) values(3,4);
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);
-- 给客服角色分配权限
insert into tb_rps(rid,pid) values(4,11);
insert into tb_rps(rid,pid) values(4,12);
-- 给行政角色分配权限
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);
```
1.2DAO实现
Shiro进行认证需要用户信息:
根据用户名查询用户信息
Shiro进行授权管理需要当前用户的角色和权限
根据用户名查询当前角色的角色列表
根据用户名查询当前用户的权限列表
1.2.1创建SpringBoot项目,整合Mybatis
1.2.2根据用户名查询用户信息
创建UserBean
import lombok.Data;
@Data
public class User {
private Integer userId;
private String userName;
private String userPwd;
private String pwdSalt;
}
//创建Dao
public interface UserDao {
public User queryUserByUsername(String username) throws Exception;
}
//mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qfedu.shiro3.dao.UserDao">
<resultMap id="userMap" type="com.qfedu.shiro3.beans.User">
<id column="user_id" property="userId"></id>
<result column="username" property="userName"/>
<result column="password" property="userPwd"/>
<result column="password_salt" property="pwdSalt"/>
</resultMap>
<select id="queryUserByUsername" resultMap="userMap">
select * from tb_users
where username=#{username}
</select>
</mapper>
1.2.3根据用户名查询当前角色的角色列表
//roledao
public interface RoleDao {
public Set<String> queryRoleNameByUserName(String username);
}
//
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qfedu.shiro3.dao.RoleDao">
<select id="queryRoleNameByUserName" resultSets="java.util.Set" resultType="string">
SELECT tb_roles.role_name FROM tb_users
INNER JOIN tb_urs on tb_users.user_id = tb_urs.uid
INNER JOIN tb_roles ON tb_urs.rid = tb_roles.role_id
where tb_users.username=#{username}
</select>
</mapper>
1.2.4根据用户名查询当前用户的权限列表
//dao
public interface PermissionDao {
public Set<String> queryPermissionByUserName(String username) throws Exception;
}
//mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qfedu.shiro3.dao.PermissionDao">
<select id="queryPermissionByUserName" resultSets="java.util.Set" resultType="string">
SELECT tb_permissions.permission_code FROM tb_users
INNER JOIN tb_urs on tb_users.user_id = tb_urs.uid
INNER JOIN tb_roles ON tb_urs.rid = tb_roles.role_id
INNER JOIN tb_rps on tb_urs.rid = tb_rps.rid
inner join tb_permissions on tb_rps.pid = tb_permissions.permission_id
where tb_users.username=#{username}
</select>
</mapper>
1.3整合Shiro
导入依赖
```xml
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
```
配置Shiro-基于Java配置方式
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
@Bean
public MyRealm getMyRealm(){
MyRealm myRealm = new MyRealm();
return myRealm;
}
//SecurityManager要完成验证,需要realm
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManage(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
filter.setSecurityManager(securityManager);
//设置拦截规则
// anon匿名用户可访问
//authc 认证用户可以访问
//user 认证用户可以访问
//perms 对应权限可以访问
//role 对应的角色可以访问
Map<String,String> filterMap=new HashMap<>();
filterMap.put("/","anon");
filterMap.put("/login.html","anon");
filterMap.put("/index.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;
}
}
自定义Realm
import com.qfedu.shiro3.beans.User;
import com.qfedu.shiro3.dao.PermissionDao;
import com.qfedu.shiro3.dao.RoleDao;
import com.qfedu.shiro3.dao.UserDao;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import javax.annotation.Resource;
import java.util.Set;
public class MyRealm extends AuthorizingRealm {
@Resource
private UserDao userDao;
@Resource
private RoleDao roleDao;
@Resource
private PermissionDao permissionDao;
@Override
public String getName() {
return "myRealm";
}
//获取授权数据:将当前用户的角色及权限查询出来
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username = (String) principalCollection.iterator().next();
//查询用户角色和权限列表
Set<String> roleName = roleDao.queryRoleNameByUserName(username);
Set<String> ps = permissionDao.queryPermissionByUserName(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roleName);
info.setStringPermissions(ps);
return info;
}
//获取认证数据
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//authenticationToken 就是传递suject。login(token)
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
String username=token.getUsername();
User user = userDao.queryUserByUsername(username);
if (user==null){
return null;
}
AuthenticationInfo info = new SimpleAuthenticationInfo(username,user.getUserPwd(),getName());
return info;
}
}
二、springboot项目应用部署
SpringBoot项目集成了web容器(Tomcat),所以SpringBoot应用是可以打包成jar直接运行的
nohup java -jar shiro4.jar