首页 > 技术文章 > spring+mybatis+shiro实战实现权限验证

blackmlik 2020-04-24 14:22 原文

数据库准备

一般要做权限验证需要五张表 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>

推荐阅读