Java Web基础入门第七十七讲 Filter(过滤器)——Filter(过滤器)常见应用(三):权限管理系统(上)

我们要设计的权限管理系统,要使用Filter实现URL级别的权限认证。那我们不禁就要想设计出的权限管理系统应该使用在哪种情景中呢?我想应该是这样的一种情景吧:在实际开发中我们经常把一些执行敏感操作的Servlet映射到一些特殊目录中,并用Filter把这些特殊目录保护起来,限制只能拥有相应访问权限的用户才能访问这些目录下的资源。从而在我们的系统中实现一种URL级别的权限功能。而且为使Filter具有通用性,Filter保护的资源和相应的访问权限应通过Filter参数的形式予以配置。

创建MVC架构的Web项目

在Eclipse中新创建一个day20的项目,导入项目所需要的开发包(jar包),创建项目所需要的包,在Java Web开发中,架构的层次是以包的形式体现出来的。
在这里插入图片描述
在这里插入图片描述
以上就是根据此项目的实际情况创建的包,可能还需要创建其他的包,这个得根据项目的需求来定了。

权限管理系统的设计和分析

我们若要设计一个这样的权限管理系统,肯定就要考虑需要设计几个对象,一般来说大概至少需要以下四个对象:
在这里插入图片描述
现在我们来思考这几个对象之间的关系,万事万物总该有那么一点联系吧!

  • 权限和资源之间的关系:若一个资源需要一个权限,这是一对一的关系;若一个权限可以控制多个资源,并且一个资源只能对应有一个控制权限,这是一对多的关系。但是在此权限管理系统中我们选择后者,即一对多的关系。
  • 权限和角色之间的关系:一个角色有多个权限,一个权限赋予多个角色,这是多对多的关系。
  • 用户和角色之间的关系:一个用户有可能拥有多个角色(多重身份),一个角色可能被赋予多个用户,这是多对多的关系。

明了上述内容之后,我们就来设计这四个对象,即开发domain层。

开发domain层

首先,我们来分析和设计权限(Privilege)这个类,该类一些基本的属性,我们忽略,而来着重分析权限和资源以及权限和角色之间的关系。

  • 在分析和设计权限(Privilege)这个类时,这个类可以不设置集合来记住它控制的哪些资源,由于在页面里面一般是没有这个需求的,我们在显示这个权限的时候,我们并不需要说这个权限控制了哪几个资源,我们只会说在显示资源的时候,说它被哪个权限控制;
  • 在分析和设计权限(Privilege)这个类时,我们有必要设计一个集合来记住这个权限授予了哪些角色吗?没有必要,一般来说,只是在显示角色的时候,我们才会说这个角色拥有哪些权限,我们是不会在页面里说在显示权限的时候,权限授予了哪些角色。

分析完了,权限(Privilege)这个类的代码实现就会一目了然,我们在cn.liayun.domain包中创建这个权限(Privilege)类,权限(Privilege)这个类的具体代码如下:

package cn.liayun.domain;

public class Privilege {
	
	private String id;
	private String name;//如添加分类的权限
	private String description;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	
}

接下来我们来分析和设计资源(Resource)这个类,该类一些基本的属性,我们忽略,而来着重分析资源和权限之间的关系。

  • 在分析和设计资源(Resource)这个类时,有没有必要设计一个属性记住资源被哪个权限控制呢?显然有必要,我们在页面显示资源的时候,我们会说这个资源被哪个权限所控制。

分析完了,资源(Resource)这个类的代码实现就会一目了然,我们在cn.liayun.domain包中创建这个资源(Resource)类,资源(Resource)这个类的具体代码如下:

package cn.liayun.domain;

public class Resource {

	private String id;
	private String uri;//如:/day20/manager/Servlet1
	private String description;
	
	private Privilege privilege;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getUri() {
		return uri;
	}

	public void setUri(String uri) {
		this.uri = uri;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Privilege getPrivilege() {
		return privilege;
	}

	public void setPrivilege(Privilege privilege) {
		this.privilege = privilege;
	}
	
}

再接下来我们来分析和设计角色(Role)这个类,该类一些基本的属性,我们忽略,而来着重分析角色和权限以及角色和用户之间的关系。

  • 思考你在页面显示一个角色的时候,你需要显示什么?我在页面里面显示一个角色的时候,这个角色应拥有哪些权限,所以说要设计一个集合来记住角色所有的权限;
  • 然后思考有没有必要设计一个集合来记住这个角色授予了多少个用户呢?一般来说没有必要,应该在显示用户的时候说这个用户拥有哪些角色,而不会说显示角色的时候,这个角色授予了哪些用户。

分析完了,角色(Role)这个类的代码实现就会一目了然,我们在cn.liayun.domain包中创建这个角色(Role)类,角色(Role)这个类的具体代码如下:

package cn.liayun.domain;

import java.util.HashSet;
import java.util.Set;

public class Role {

	private String id;
	private String name;
	private String description;
	
	private Set<Privilege> privileges = new HashSet<Privilege>();

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Set<Privilege> getPrivileges() {
		return privileges;
	}

	public void setPrivileges(Set<Privilege> privileges) {
		this.privileges = privileges;
	}
	
}

最后我们来分析和设计用户(User)这个类,该类一些基本的属性,我们忽略,而来着重分析用户和角色之间的关系。

  • 思考:在用户这边有没有必要设计一个集合来记住这个用户授予了哪些角色呢?显然有必要。

分析完了,用户(User)这个类的代码实现就会一目了然,我们在cn.liayun.domain包中创建这个用户(User)类,用户(User)这个类的具体代码如下:

package cn.liayun.domain;

import java.util.HashSet;
import java.util.Set;

public class User {
	
	private String id;
	private String username;
	private String password;
	private String description;
	
	private Set<Role> roles = new HashSet<Role>();

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Set<Role> getRoles() {
		return roles;
	}

	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}
	
}

至此,domain层就编写完了。如果说有人还不明白,我们就用图来表示这四个对象之间的关系,这样或许会更加清楚。
在这里插入图片描述
设计完这四个类之后,我们就要在数据库中创建这四个类所对应的数据库表及其中间表了,完整的建表SQL语句如下:

create database day20;
use day20;

create table privilege
(
    id varchar(40) primary key,
    name varchar(100) not null unique,
    description varchar(255)
);

create table resource 
(
    id varchar(40) primary key,
    uri varchar(255) not null unique,
    description varchar(255),
    privilege_id varchar(40),
    constraint privilege_id_FK foreign key(privilege_id) references privilege(id)
);

create table role
(
    id varchar(40) primary key,
    name varchar(100) not null unique,
    description varchar(255)
);

create table role_privilege
(
    role_id varchar(40),
    privilege_id varchar(40),
    primary key(role_id,privilege_id),
    constraint role_id_FK foreign key(role_id) references role(id),
    constraint privilege_id_FK1 foreign key(privilege_id) references privilege(id)
);

create table user 
(
    id varchar(40) primary key,
    username varchar(40) not null unique,
    password varchar(40) not null,
    description varchar(255)
);

create table user_role
(
    user_id varchar(40),
    role_id varchar(40),
    primary key(user_id,role_id),
    constraint user_id_FK foreign key(user_id) references user(id),
    constraint role_id_FK1 foreign key(role_id) references role(id)
);

开发数据访问层(dao、dao.impl)

为了提升程序的数据库访问性能,我们通常应在项目开发中使用C3P0数据源。所以应在类目录下加入C3P0的配置文件:c3p0-config.xml。
在这里插入图片描述
c3p0-config.xml配置文件的内容如下:

<c3p0-config>
	<!-- 
		C3P0的缺省(默认)配置,
		如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource();”这样写就表示使用的是C3P0的缺省(默认)配置信息来创建数据源
	-->
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/day20</property>
		<property name="user">root</property>
		<property name="password">liayun</property>
		
		<property name="initialPoolSize">10</property>
		<property name="maxIdleTime">30</property><!-- 最大空闲时间 -->
		<property name="maxPoolSize">20</property>
		<property name="minPoolSize">5</property>
		<property name="maxStatements">200</property>
	</default-config>

	<!-- 
		C3P0的命名配置,
		如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource("mysql");”这样写就表示使用的是name为mysql的配置信息来创建数据源
	-->
	<named-config name="mysql">
		<property name="acquireIncrement">50</property>
		<property name="initialPoolSize">100</property>
		<property name="minPoolSize">50</property>
		<property name="maxPoolSize">1000</property>

		<!-- intergalactoApp adopts a different approach to configuring statement 
			caching -->
		<property name="maxStatements">0</property>
		<property name="maxStatementsPerConnection">5</property>
	</named-config>
	
	<named-config name="oracle">
		<property name="acquireIncrement">50</property>
		<property name="initialPoolSize">100</property>
		<property name="minPoolSize">50</property>
		<property name="maxPoolSize">1000</property>

		<!-- intergalactoApp adopts a different approach to configuring statement 
			caching -->
		<property name="maxStatements">0</property>
		<property name="maxStatementsPerConnection">5</property>
	</named-config>
</c3p0-config>

也是为了简化JDBC的开发,我们使用Apache组织提供的一个开源JDBC工具类库——commons-dbutils-1.6.jar。然后在cn.liayun.utils包下创建一个工具类——JdbcUtils.java,用于读取C3P0的xml配置文件创建数据源,该工具类的具体代码如下:

package cn.liayun.utils;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JdbcUtils {
	
	private static DataSource ds;
	
	static {
		ds = new ComboPooledDataSource(); 
	}
	
	public static DataSource getDataSource() {
		return ds;
	}
	
}

准备好以上这些工作之后,我们正式步入开发数据库访问层的阶段。
我们首先开发ResourceDao类,在cn.liayun.dao包下创建一个ResourceDao类,该类的具体代码如下:

package cn.liayun.dao;

import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.liayun.domain.Privilege;
import cn.liayun.domain.Resource;
import cn.liayun.utils.JdbcUtils;

public class ResourceDao {
	
	//添加资源进数据库
	public void add(Resource r) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "insert into resource(id,uri,description) values(?,?,?)";
			Object[] params = {r.getId(), r.getUri(), r.getDescription()};
			runner.update(sql, params);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	//根据资源的uri进行查找
	public Resource find(String uri) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from resource where uri=?";
			Resource r = runner.query(sql, uri, new BeanHandler<Resource>(Resource.class));
			
			if (r == null) {
				return null;
			}
			
			//得到控制资源的权限(涉及到多表查询)
			sql = "select p.* from resource r, privilege p where r.uri=? and p.id=r.privilege_id";
			Privilege p = runner.query(sql, uri, new BeanHandler<Privilege>(Privilege.class));
			
			r.setPrivilege(p);
			return r;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	//根据资源的id进行查找
	public Resource findById(String id) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from resource where id=?";
			Resource r = runner.query(sql, id, new BeanHandler<Resource>(Resource.class));
			
			//得到控制资源的权限(涉及到多表查询)
			sql = "select p.* from resource r, privilege p where r.id=? and p.id=r.privilege_id";
			Privilege p = runner.query(sql, id, new BeanHandler<Privilege>(Privilege.class));
			
			r.setPrivilege(p);
			return r;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public List<Resource> getAll() {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from resource";
			List<Resource> list = runner.query(sql, new BeanListHandler<Resource>(Resource.class));
			
			//还要找出每个资源,控制它的权限(涉及到多表查询)
			for (Resource r : list) {
				sql = "select p.* from resource r, privilege p where r.id=? and p.id=r.privilege_id";
				Privilege p = runner.query(sql, r.getId(), new BeanHandler<Privilege>(Privilege.class));
				r.setPrivilege(p);
			}
			return list;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	//更新资源的权限,也就是为资源授予控制权限
	public void updatePrivilege(Resource r, Privilege p) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "update resource set privilege_id=? where id=?";
			Object[] params = {p.getId(), r.getId()};
			runner.update(sql, params);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
}

接下来我们开发PrivilegeDao类,在cn.liayun.dao包下创建一个PrivilegeDao类,该类的具体代码如下:

package cn.liayun.dao;

import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.liayun.domain.Privilege;
import cn.liayun.utils.JdbcUtils;

public class PrivilegeDao {

	public void add(Privilege p) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "insert into privilege(id,name,description) values(?,?,?)";
			Object[] params = {p.getId(), p.getName(), p.getDescription()};
			runner.update(sql, params);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public Privilege find(String id) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from privilege where id=?";
			return runner.query(sql, id, new BeanHandler<Privilege>(Privilege.class));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public List<Privilege> getAll() {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from privilege";
			return runner.query(sql, new BeanListHandler<Privilege>(Privilege.class));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
}

再接下来我们开发RoleDao类,在cn.liayun.dao包下创建一个RoleDao类,该类的具体代码如下:

package cn.liayun.dao;

import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.liayun.domain.Privilege;
import cn.liayun.domain.Role;
import cn.liayun.utils.JdbcUtils;

public class RoleDao {

	public void add(Role role) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "insert into role(id,name,description) values(?,?,?)";
			Object[] params = {role.getId(), role.getName(), role.getDescription()};
			runner.update(sql, params);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public Role find(String id) {
		try {
			//查找角色的基本信息
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from role where id=?";
			Role role = runner.query(sql, id, new BeanHandler<Role>(Role.class));
			
			//找出角色的所有权限
			sql = "select * from role_privilege rp,privilege p where rp.role_id=? and p.id=rp.privilege_id";
			List<Privilege> list = runner.query(sql, id, new BeanListHandler<Privilege>(Privilege.class));
			
			role.getPrivileges().addAll(list);
			return role;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public List<Role> getAll() {
		try {
			//查找角色的基本信息
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from role";
			List<Role> list = runner.query(sql, new BeanListHandler<Role>(Role.class));
			
			//找出每一个角色拥有的所有权限
			for (Role r : list) {
				sql = "select * from role_privilege rp,privilege p where rp.role_id=? and p.id=rp.privilege_id";
				List<Privilege> list1 = runner.query(sql, r.getId(), new BeanListHandler<Privilege>(Privilege.class));
				r.getPrivileges().addAll(list1);
			}
			return list;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/*
	 * 简便的做法:更新某个角色的所有权限,一上来就把角色原来的权限都删了,再为其更新!
	 *          这样做,同时还有一个好处,有时候想把某一个角色所有权限全部清了,什么都不要勾,一点更新按钮就全部清了!
	 */
	//更新角色的权限
	public void updateRolePrivilege(Role role, List<Privilege> privileges) {
		try {
			//删除角色拥有的所有权限
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "delete from role_privilege where role_id=?";
			runner.update(sql, role.getId());
			
			//再为角色赋予新的权限
			for (Privilege p : privileges) {
				sql = "insert into role_privilege(role_id,privilege_id) values(?,?)";
				Object[] params = {role.getId(), p.getId()};
				runner.update(sql, params);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
}

其中更新角色的权限,写起来是有些麻烦的,因为一个角色就有可能拥有多个权限。考虑到这点,我们可以采用简便的方法,即首先删除掉角色拥有的所有权限,然后再为角色赋予新的权限。如果按照这种简便的方式来写代码,当更新角色的权限时,什么也不勾选的话,这就只相当于删除掉角色拥有的所有权限,如果勾选了若干权限,就能为角色赋予若干权限了。
最后,我们开发UserDao类,在cn.liayun.dao包下创建一个UserDao类,该类的具体代码如下:

package cn.liayun.dao;

import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.liayun.domain.Role;
import cn.liayun.domain.User;
import cn.liayun.utils.JdbcUtils;

public class UserDao {

	public void add(User user) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "insert into user(id,username,password,description) values(?,?,?,?)";
			Object[] params = {user.getId(), user.getUsername(), user.getPassword(), user.getDescription()};
			runner.update(sql, params);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public User find(String id) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from user where id=?";
			User user = runner.query(sql, id, new BeanHandler<User>(User.class));
			if (user == null) {
				return null;
			}
			
			//找出用户的所有角色
			sql = "select * from user_role ur,role r where ur.user_id=? and r.id=ur.role_id";
			List<Role> list = runner.query(sql, id, new BeanListHandler<Role>(Role.class));
			user.getRoles().addAll(list);
			
			return user;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	//用户登录
	public User find(String username, String password) {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from user where username=? and password=?";
			Object[] params = {username, password};
			User user = runner.query(sql, params, new BeanHandler<User>(User.class));
			if (user == null) {
				return null;
			}
			
			//找出用户的所有角色
			sql = "select * from user_role ur,role r where ur.user_id=? and r.id=ur.role_id";
			List<Role> list = runner.query(sql, user.getId(), new BeanListHandler<Role>(Role.class));
			user.getRoles().addAll(list);
			
			return user;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	//为用户赋予角色(更新用户的角色)
	public void updateUserRoles(User user, List<Role> roles) {
		try {
			//先删除用户拥有的所有角色
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "delete from user_role where user_id=?";
			runner.update(sql, user.getId());
			
			//再为用户赋予新的角色
			for (Role r : roles) {
				//最好把多条sql语句做在一个批处理里面去,批量发送sql语句
				sql = "insert into user_role(user_id,role_id) values(?,?)";
				Object[] params = {user.getId(), r.getId()};
				runner.update(sql, params);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public List<User> getAll() {
		try {
			QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
			String sql = "select * from user";
			List<User> list = runner.query(sql, new BeanListHandler<User>(User.class));
			/*
			 * List集合里面保存了一个个User,每一个User并不知道它所拥有的角色,
			 * 这个地方可以偷懒,不写代码为每一个用户找出其所有角色,为什么呢?
			 * 在页面中去显示所有用户的时候,这时并不需要去显示每一个用户拥有哪些角色,
			 * 点进去的时候,查看用户细节的时候才需要显示。
			 */
			return list;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	//查询出一个用户拥有的所有权限???——放在Service层里面了
}

至此,整个数据库访问层就开发完了。既然开发完了,那么我们就来开发业务逻辑层。

开发service层(service层对web层提供所有的业务服务)

在cn.liayun.service包下创建一个SecurityService类,用来对web层提供资源、权限、角色和用户相关的服务,该类的具体代码如下:

package cn.liayun.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import cn.liayun.dao.PrivilegeDao;
import cn.liayun.dao.ResourceDao;
import cn.liayun.dao.RoleDao;
import cn.liayun.dao.UserDao;
import cn.liayun.domain.Privilege;
import cn.liayun.domain.Resource;
import cn.liayun.domain.Role;
import cn.liayun.domain.User;

public class SecurityService {

	private ResourceDao rDao = new ResourceDao();
	private PrivilegeDao pDao = new PrivilegeDao();
	private RoleDao roleDao = new RoleDao();
	private UserDao uDao = new UserDao();
	
	/**************************************************************************************
	 * 提供资源相关的服务
	 **************************************************************************************/
	public void addResource(Resource r) {
		rDao.add(r);
	}
	
	public Resource findResource(String uri) {
		return rDao.find(uri);
	}
	
	public Resource findResourceByID(String id) {
		return rDao.findById(id);
	}
	
	public List<Resource> getAllResource() {
		return rDao.getAll();
	}
	
	//更新控制资源的权限
	public void updateResourcePrivilege(String resourceid, String privilegeid) {
		Resource r = rDao.findById(resourceid);
		Privilege p = pDao.find(privilegeid);
		rDao.updatePrivilege(r, p);
	}
	
	/**************************************************************************************
	 * 提供权限相关的服务
	 **************************************************************************************/
	public void addPrivilege(Privilege p) {
		pDao.add(p);
	}
	
	public Privilege findPrivilege(String id) {
		return pDao.find(id);
	}
	
	public List<Privilege> getAllPrivilege() {
		return pDao.getAll();
	}
 	
	/**************************************************************************************
	 * 提供角色相关的服务
	 **************************************************************************************/
	public void addRole(Role role) {
		roleDao.add(role);
	}
	
	public Role findRole(String id) {
		return roleDao.find(id);
	}
	
	public List<Role> getAllRole() {
		return roleDao.getAll();
	}
	
	//为某个角色授权,即更新角色拥有的权限
	public void updateRolePrivilege(String roleid, String[] privilege_ids) {
		Role role = roleDao.find(roleid);
		List<Privilege> list = new ArrayList<Privilege>();
		for (int i = 0; privilege_ids != null && i < privilege_ids.length; i++) {
			Privilege p = pDao.find(privilege_ids[i]);
			list.add(p);
		}
		roleDao.updateRolePrivilege(role, list);
	}
	
	/**************************************************************************************
	 * 提供用户相关的服务
	 **************************************************************************************/
	public void addUser(User user) {
		uDao.add(user);
	}
	
	public User findUser(String id) {
		return uDao.find(id);
	}

	public User findUser(String username, String password) {
		return uDao.find(username, password);
	}
	
	public List<User> getAllUser() {
		return uDao.getAll();
	}
	
	//更新用户拥有的角色
	public void updateUserRole(String userid, String[] roleids) {
		User user = uDao.find(userid);
		List<Role> list = new ArrayList<Role>();
		for (int i = 0; roleids != null && i < roleids.length; i++) {
			Role r = roleDao.find(roleids[i]);
			list.add(r);
		}
		uDao.updateUserRoles(user, list);
	}
	
	//得到某一个用户所拥有的所有权限
	public List<Privilege> getUserAllPrivilege(String userid) {
		List<Privilege> allPrivilege = new ArrayList<Privilege>();
		
		User user = uDao.find(userid);//找用户的角色时,并没有找出这个角色的所有权限,所以Set集合里面每一个角色并没有与它相关的权限
		Set<Role> roles = user.getRoles();
		for (Role r : roles) {
			r = roleDao.find(r.getId());
			Set<Privilege> privileges = r.getPrivileges();
			allPrivilege.addAll(privileges);
		}
		
		return allPrivilege;
	}
}

在SecurityService类中,编写对web层提供用户相关的服务时,尤其是在编写得到某个用户拥有的所有权限的方法——getUserAllPrivilege(String userid)时,可能要更加麻烦 ,所以我们更应该耐心一点。思考一下我们为什么要得到某个用户拥有的所有权限呢?要回答这个问题,就要看看我们的网站的首页了,或许网站首页——index.jsp就是这样子的:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/itcast" prefix="itcast" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <a href="/day20/manager/Servlet1">添加分类</a>
    <a href="/day20/manager/Servlet2">删除分类</a>
    <a href="/day20/manager/Servlet3">修改分类</a>
    <a href="/day20/manager/Servlet4">查找分类</a>
</body>
</html>

若网站首页就是以上这个样子的,那么对于该网站来说,就有四种权限,即:

  1. 添加分类;
  2. 删除分类;
  3. 修改分类;
  4. 查找分类。

可以总结出一句话:网站有什么权限,其实就是由它对外提供的超链接来决定的!我们不要东拉西扯太远了,还是回到这个问题上来,有人访问网站首页,他一点“添加分类”的超链接,一个过滤器就把这个请求拦截下来,拦截下来之后,检查此人有没有这个权限,即有没有添加分类的权限,那么为了检查某个用户有没有添加分类的权限,所以就要得到用户的所有权限。我们知道原因之后,就要编码实现这个业务逻辑了,怎么去写代码实现呢?

  • 得到该用户拥有的所有角色。虽然得到该用户拥有的所有角色,但是并没有找出每个角色被赋予的所有权限,即user.getRoles()得到的Set<Role>集合里面每一个角色并没有与它相关的权限;
  • 遍历user.getRoles()得到的Set<Role>集合,找出每个角色下的所有权限。
  • 12
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李阿昀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值