spring+mybatis+shiro实战实现权限验证
数据库准备
一般要做权限验证需要五张表 user,user_role,role,role_permission,permission分别对应用户,角色,权限以及两个关联表,用户绑定角色,而权限只和角色有关,例如:
用户1-----角色1----person:query,person:update,person:delete,person:add
用户2-----角色2---person:query
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`perid` int(11) NOT NULL AUTO_INCREMENT,
`pername` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`percode` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`perid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES (1, '用户查询', 'person:query');
INSERT INTO `permission` VALUES (2, '用户添加', 'person:add');
INSERT INTO `permission` VALUES (3, '用户修改', 'person:update');
INSERT INTO `permission` VALUES (4, '用户删除', 'person:delete');
INSERT INTO `permission` VALUES (5, '导出用户', 'person:export');
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`roleid` int(11) NOT NULL AUTO_INCREMENT,
`rolename` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`roleid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, '超级管理员');
INSERT INTO `role` VALUES (2, 'CEO');
INSERT INTO `role` VALUES (3, '保安');
-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`perid` int(255) NULL DEFAULT NULL,
`roleid` int(11) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role_permission
-- ----------------------------
INSERT INTO `role_permission` VALUES (1, 1);
INSERT INTO `role_permission` VALUES (2, 1);
INSERT INTO `role_permission` VALUES (3, 1);
INSERT INTO `role_permission` VALUES (4, 1);
INSERT INTO `role_permission` VALUES (1, 2);
INSERT INTO `role_permission` VALUES (2, 2);
INSERT INTO `role_permission` VALUES (3, 2);
INSERT INTO `role_permission` VALUES (1, 3);
INSERT INTO `role_permission` VALUES (5, 3);
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`userpwd` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`sex` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'zhangsan', '639ffb0cbcca39d4fff8348844b1974e', '男', '武汉');
INSERT INTO `user` VALUES (2, 'lisi', '0d303fa8e2e2ca98555f23a731a58dd9', '女', '北京');
INSERT INTO `user` VALUES (3, 'wangwu', '473c41db9af5cc0d90e7adfd2b6d9180', '女', '成都');
-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`userid` int(11) NULL DEFAULT NULL,
`roleid` int(11) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1);
INSERT INTO `user_role` VALUES (2, 2);
INSERT INTO `user_role` VALUES (3, 3);
SET FOREIGN_KEY_CHECKS = 1;
shiro的spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 声明凭证匹配器 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5"></property>
<property name="hashIterations" value="2"></property>
</bean>
<!-- 声明userRealm -->
<bean id="userRealm" class="com.sxt.realm.UserRealm">
<!-- 注入凭证匹配器 -->
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
<!-- 配置SecurityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 注入realm -->
<property name="realm" ref="userRealm"></property>
</bean>
<!-- 配置shiro的过滤器 这里面的id必须和web.xml里面的配置一样 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" >
<!-- 注入安全管理器 -->
<property name="securityManager" ref="securityManager"></property>
<!-- 注入未登陆的跳转页面 默认的是webapp/login.jsp-->
<property name="loginUrl" value="/index.jsp"></property>
<!-- 注入未授权的访问页面 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"></property>
<!-- 配置过滤器链 -->
<property name="filterChainDefinitions">
<value>
<!-- 放行index.jsp -->
/index.jsp*=anon
<!-- 放行跳转到登陆页面的路径 -->
/login/toLogin*=anon
<!-- 放行登陆的请求 -->
/login/login*=anon
<!-- 设置登出的路径 -->
/login/logout*=logout
<!-- 设置其它路径全部拦截 -->
/**=authc
</value>
</property>
</bean>
</beans>
其他的配置文件,就不写了,和普通的spring项目差不多,然后创建三个service,三个Mapper文件
#查询用户名是否存在
select * from user where username=#{username}
#根据用户id查询对应的角色
SELECT t1.* FROM role t1 INNER JOIN `user_role` t2 ON t1.roleid = t2.roleid WHERE t2.userid =#{userid}
#根据用户id查询对应的权限
SELECT t1.* FROM
permission t1
INNER JOIN `user_role` t2
INNER JOIN role_permission t3 ON t2.roleid = t3.roleid
AND t1.perid = t3.perid
WHERE
t2.userid =#{userid}
创建ActivierUser
方便封装
public class ActivierUser {
private User user;
private List<String> roles;
private List<String> permissions;
public ActivierUser() {
}
public ActivierUser(User user, List<String> roles, List<String> permissions) {
super();
this.user = user;
this.roles = roles;
this.permissions = permissions;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<String> getRoles() {
return roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
public List<String> getPermissions() {
return permissions;
}
public void setPermissions(List<String> permissions) {
this.permissions = permissions;
}
}
创建自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
@Override
public String getName() {
return this.getClass().getSimpleName();
}
/*
*
* 授权
* */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
ActivierUser activierUser = (ActivierUser) principalCollection.getPrimaryPrincipal();
List<String> permissions = activierUser.getPermissions();
List<String> roles = activierUser.getRoles();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if (roles != null && roles.size()>0){
info.addRoles(roles);
}
if (permissions != null && permissions.size()>0){
info.addStringPermissions(permissions);
}
return info;
}
/*
* 认证
* */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//拿到用户名
String username = token.getPrincipal().toString();
//查询用户名是否存在
User user = userService.queryUserByName(username);
if(user == null){
return null;
}
//查询角色和权限
List<Role> roleList = roleService.queryRoleList(user.getUserid().toString());
ArrayList<String> roles = new ArrayList<>();
for (Role role : roleList) {
roles.add(role.getRolename());
}
ArrayList<String> permissions = new ArrayList<>();
List<Permission> permissionList = permissionService.queryPermissionByUserId(user.getUserid().toString());
for (Permission permission : permissionList) {
permissions.add(permission.getPercode());
}
//盐
ByteSource salt = ByteSource.Util.bytes(user.getUsername() + user.getAddress());
ActivierUser activierUser = new ActivierUser(user,roles,permissions);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activierUser,user.getUserpwd(),salt,this.getName());
return info;
}
}
Controller层
LoginController.java
@RequestMapping("login")
@Controller
public class LoginController {
/**
* 跳转到登陆页面
*/
@RequestMapping("toLogin")
public String toLogin() {
return "login";
}
/**
* 做登陆
*/
@RequestMapping("login")
public String login(String username,String pwd,
HttpSession session,Model model) throws Exception {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, pwd);
try {
subject.login(token);
ActivierUser activierUser = (ActivierUser) subject.getPrincipal();
session.setAttribute("user",activierUser.getUser());
return "redirect:/login/toUserManager.action";
}catch (IncorrectCredentialsException e) {
System.err.println("密码不正确");
model.addAttribute("error", "密码不正确");
} catch (UnknownAccountException e) {
System.err.println("用户名不存在");
model.addAttribute("error", "用户名不存在");
}
return "redirect:/login.jsp";
}
@RequestMapping("/toUserManager")
public String toUserManager() {
return "list";
}
}
权限控制标签
<shiro:hasPermission name="person:query">
<h1><a href="user/query.action">查询用户</a></h1>
</shiro:hasPermission>
<shiro:hasPermission name="person:add">
<h1><a href="user/add.action">添加用户</a></h1>
</shiro:hasPermission>
<shiro:hasPermission name="person:update">
<h1><a href="user/update.action">修改用户</a></h1>
</shiro:hasPermission>
<shiro:hasPermission name="person:delete">
<h1><a href="user/delete.action">删除用户</a></h1>
</shiro:hasPermission>
<shiro:hasPermission name="person:export">
<h1><a href="user/export.action">导出用户</a></h1>
</shiro:hasPermission>