一、功能介绍
每个网站都涉及到访问权限的控制。每个站点资源都需要被管理起来,用户只有具有访问某个资源的特定权限,才能够访问,否则拒绝访问。
二、项目分析
我们要实现网站的访问权限控制,就应该从 URI 入手,站点的每个资源都用唯一的 URI 描述,我们为想要管理起来的 URI 增加上权限属性,当用户访问资源时我们要先检查用户是否具有权限。这个项目我采用过滤器技术实现权限拦截,下一个项目我将采用注解+动态代理实现权限的拦截。
我们需要编写一个过滤器,拦截用户的每个访问请求。再依据 URI 判断是否需要权限。这个是比较简单的,关键就是我们如何将这种权限关系描述出来,如果使用过滤器技术,我们就不得不使用数据库来将每个权限、资源等保存起来。一个资源需要一个权限,一个权限对应多个角色,一个角色可以拥有多个权限,一个用户拥有多个角色,一个角色又可以被多个用户引用。所以资源与权限是一对一关系,权限与角色是多对多关系,角色与用户也是多对多关系。因此在数据库我们需要6张表来保存关系。
一、对象关系 资源、权限、角色、用户
资源 ------> 权限 一对多
权限 <-----> 角色 多对多
角色 <-----> 用户 多对多
资源:
String id 编号
String uri 资源uri
String description 描述
Permission permission 该资源需要的权限
权限:
String id 编号
String name 权限名
String description 权限描述
角色:
String id 编号
String name 角色名
String description 角色描述
Set<Permission> set 该角色具有的权限
用户:
String id 编号
String username 用户名
String password 密码
Set<Role> set 该用户都具有的角色
二、数据库实现
create database if not exists sys_permission;
use sys_permission;
create table if not exists resource(
id varchar(40) primary key,
uri varchar(255) unique,
description varchar(255),
permission_id varchar(40),
constraint rPermission_id_FK foreign key(permission_id) references permission(id)
);
create table if not exists permission(
id varchar(40) primary key,
name varchar(40) unique,
description varchar(255)
);
create table if not exists role(
id varchar(40) primary key,
name varchar(40) unique,
description varchar(255)
);
create table if not exists user(
id varchar(40) primary key,
username varchar(40) not null unique,
password varchar(40) not null
);
create table if not exists permission_role(
permission_id varchar(40) not null,
role_id varchar(40) not null,
constraint permission_id_FK foreign key(permission_id) references permission(id),
constraint role_id_FK foreign key(role_id) references role(id),
constraint primary key(permission_id,role_id)
);
create table if not exists user_role(
user_id varchar(40) not null,
role_id varchar(40) not null,
constraint user_id_FK foreign key(user_id) references user(id),
constraint uRole_id_FK foreign key(role_id) references role(id),
constraint primary key(user_id,role_id)
);
三、项目新技术
1、采用 sitemesh 框架为每个页面动态增加模版。原理:sitemesh 实际上也是一个过滤器,当用户访问一个页面时,sitemesh 将请求拦截下来,在服务器以后使用 response 写出数据的时候,实际上是写到了代理对象的缓存中,当数据读写完,sitemesh 再对数据进行包装之后再打给浏览器。
2、采用 windows 命令初始化数据库。我们将数据库的初始化信息写在文件中,当在浏览器访问初始化 Servlet 时,将使用 windows 命令将文件中的数据导入到 mysql 中。
package cn.dk.domain;
public class Permission {
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;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Permission other = (Permission) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
package cn.dk.domain;
public class Resource {
private String id;
private String uri;
private String description;
private Permission permission;
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 Permission getPermission() {
return permission;
}
public void setPermission(Permission permission) {
this.permission = permission;
}
}
package cn.dk.domain;
import java.util.HashSet;
import java.util.Set;
public class Role {
public Role() {
super();
this.permissions = new HashSet<Permission>();
}
private String id;
private String name;
private String description;
private Set<Permission> permissions;
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<Permission> getPermissions() {
return permissions;
}
public void setPermissions(Set<Permission> permissions) {
this.permissions = permissions;
}
}
package cn.dk.domain;
import java.util.HashSet;
import java.util.Set;
public class User {
public User(){
super();
this.roles = new HashSet<Role>();
}
private String id;
private String username;
private String password;
private Set<Role> roles;
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 Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
package cn.dk.dao;
import java.util.List;
import cn.dk.domain.Permission;
public interface IPermissionDao {
// 插入新权限
void insertPermission(Permission permission);
// 删除权限
void deletePermission(String id);
// 根据id查找权限
Permission findPermissionById(String id);
// 查找所有权限
@SuppressWarnings("unchecked")
List<Permission> findAllPermission();
}
package cn.dk.dao;
import java.util.List;
import cn.dk.domain.Resource;
public interface IResourceDao {
// 增加资源
void insertResource(Resource resource);
// 修改资源
void updateResource(Resource resource);
// 查找所有资源
@SuppressWarnings("unchecked")
List<Resource> findAllResource();
// 根据uri查找资源
Resource findResourceByURI(String uri);
// 根据id查找资源
Resource findResourceById(String id);
// 删除资源
void deleteResource(String id);
}
package cn.dk.dao;
import java.util.List;
import cn.dk.domain.Role;
public interface IRoleDao {
// 新增角色
void insertRole(Role role);
// 更新角色
void updateRole(Role role);
// 删除角色
void deleteRole(String id);
// 根据id查找角色
@SuppressWarnings("unchecked")
Role findRoleById(String id);
// 查找所有角色
@SuppressWarnings("unchecked")
List<Role> fineAllRole();
}
package cn.dk.dao;
import java.util.List;
import cn.dk.domain.User;
public interface IUserDao {
// 插入用户
void insertUser(User user);
// 更新用户
void updateUser(User user);
// 删除用户
void deleteUser(String id);
// 根据id查找用户
@SuppressWarnings("unchecked")
User findUserById(String id);
// 查找所有用户
@SuppressWarnings("unchecked")
List<User> findAllUser();
User login(String username, String password);
}
package cn.dk.dao.impl;
import java.sql.SQLException;
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.dk.dao.IPermissionDao;
import cn.dk.domain.Permission;
import cn.dk.utils.DBUtils;
public class PermissionDaoImpl implements IPermissionDao {
// 插入新权限
public void insertPermission(Permission permission) {
QueryRunner runner = new QueryRunner(DBUtils.getDataSource());
String sql = "insert into permission (id,name,description) values(?,?,?)";
Object[] params = { permission.getId(), permission.getName(),
permission.getDescription() };
try {
runner.update(sql, params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 删除权限
public void deletePermission(String id) {
QueryRunner runer = new QueryRunner(DBUtils.getDataSource());
String sql = "update resource set permission_id=null where permission_id=?";
try {
runer.update(sql, id);
sql = "delete from permission where id=?";
runer.update(sql, id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 根据id查找权限
public Permission findPermissionById(String id) {
QueryRunner runer = new QueryRunner(DBUtils.getDataSource());
String sql = "select id,name,description from permission where id=?";
Object[] params = { id };
try {
return (Permission) runer.query(sql, new BeanHandler(
Permission.class), params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 查找所有权限
@SuppressWarnings("unchecked")
public List<Permission> findAllPermission() {
List<Permission> list = null;
QueryRunner runer = new QueryRunner(DBUtils.getDataSource());
String sql = "select id,name,description from permission";
try {
list = (List<Permission>) runer.query(sql, new BeanListHandler(
Permission.class));
} catch (SQLException e) {
throw new RuntimeException(e);
}
return list;
}
}
package cn.dk.dao.impl;
import java.sql.SQLException;
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.dk.dao.IResourceDao;
import cn.dk.domain.Permission;
import cn.dk.domain.Resource;
import cn.dk.utils.DBUtils;
public class ResourceDaoImpl implements IResourceDao {
// 增加资源
public void insertResource(Resource resource) {
QueryRunner runner = new QueryRunner(DBUtils.getDataSource());
String sql = "insert into resource (id,uri,description,permission_id) values(?,?,?,?)";
Object[] params = { resource.getId(), resource.getUri(),
resource.getDescription(), resource.getPermission().getId() };
try {
runner.update(sql, params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 修改资源
public void updateResource(Resource resource) {
QueryRunner runner = new QueryRunner(DBUtils.getDataSource());
String sql = "update resource set uri=?,description=?,permission_id=? where id=?";
Object[] params = { resource.getUri(), resource.getDescription(),
resource.getPermission().getId(), resource.getId() };
try {
runner.update(sql, params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 查找所有资源
@SuppressWarnings("unchecked")
public List<Resource> findAllResource() {
List<Resource> list = null;
QueryRunner runner = new QueryRunner(DBUtils.getDataSource());
String sql = "select id,uri,description from resource";
try {
list = (List<Resource>) runner.query(sql, new BeanListHandler(
Resource.class));
for (Resource resource : list) {
sql = "select p.id,p.name,p.description from permission p,resource r where r.permission_id=p.id and r.id=?";
Object[] params = { resource.getId() };
Permission permission = (Permission) runner.query(sql,
new BeanHandler(Permission.class), params);
resource.setPermission(permission);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return list;
}
// 根据uri查找资源
public Resource findResourceByURI(String uri) {
QueryRunner runner = new QueryRunner(DBUtils.getDataSource());
String sql = "select id,uri,description from resource where uri=?";
Object[] params = { uri };
try {
Resource resource = (Resource) runner.query(sql, new BeanHandler(
Resource.class), params);
if (resource == null)
return null;
sql = "select p.id,p.name,p.description from permission p,resource r where r.permission_id=p.id and r.id=?";
params = new Object[] { resource.getId() };
Permission permission = (Permission) runner.query(sql,
new BeanHandler(Permission.class), params);
resource.setPermission(permission);
return resource;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 根据id查找资源
public Resource findResourceById(String id) {
QueryRunner runner = new QueryRunner(DBUtils.getDataSource());
String sql = "select id,uri,description from resource where id=?";
Object[] params = { id };
try {
Resource resource = (Resource) runner.query(sql, new BeanHandler(
Resource.class), params);
sql = "select p.id,p.name,p.description from permission p,resource r where r.permission_id=p.id and r.id=?";
params = new Object[] { resource.getId() };
Permission permission = (Permission) runner.query(sql,
new BeanHandler(Permission.class), params);
resource.setPermission(permission);
return resource;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 删除资源
public void deleteResource(String id) {
QueryRunner runner = new QueryRunner(DBUtils.getDataSource());
String sql = "delete from resource where id=?";
Object[] p