权限控制案例(细粒度)

时间:2022-11-29 18:59:40

权限控制案例

权限控制案例(细粒度)

利用注解和动态代理来完成权限控制的功能

案例实现分析
   * 创建数据库表
   * 对应数据库表,创建JavaBean
   * 导入必要的Jar包
   * 完成用户登录逻辑、功能跳转逻辑.
   * 利用注解+动态代理实现权限控制.
     * 注解:为业务逻辑层的配置权限信息.

@Target(ElementType.METHOD)
	@Retention(RetentionPolicy.RUNTIME)
	public @interface Privilegeinfo {

		String value();
		
	}
* 需要将注解信息,配置到业务逻辑类的方法中.

@Override
	@Privilegeinfo("添加图书")
	public void addBook(Userinfo userinfo) {
		
	}

	@Override
	@Privilegeinfo("修改图书")
	public void editBook(Userinfo userinfo) {
		
	}

	@Override
	@Privilegeinfo("查看图书")
	public void lookBook(Userinfo userinfo) {
		
	}

	@Override
	@Privilegeinfo("删除图书")
	public void delBook(Userinfo userinfo) {
		
	}
 * 利用动态代理读取当前用户是否具有这个权限.

数据库:

create DATABASE day0110;

USE day0110;
#用户信息表
CREATE TABLE userinfo(  
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(40),
  PASSWORD VARCHAR(40)
);
INSERT INTO userinfo VALUES(NULL,'zhangwuji','123');
INSERT INTO userinfo VALUES(NULL,'zhouzhiruo','123');
INSERT INTO userinfo VALUES(NULL,'zhaomin','123');

#功能表
CREATE TABLE PRIVILEGES(
   id INT PRIMARY KEY AUTO_INCREMENT,
   NAME VARCHAR(40)
);

INSERT INTO PRIVILEGES VALUES(NULL,'添加图书');
INSERT INTO PRIVILEGES VALUES(NULL,'修改图书');
INSERT INTO PRIVILEGES VALUES(NULL,'查看图书');
INSERT INTO PRIVILEGES VALUES(NULL,'删除图书');

#用户权限表
CREATE TABLE userprivilege(
   user_id INT ,
   privilege_id INT,
   FOREIGN KEY(user_id) REFERENCES userinfo(id),
   FOREIGN KEY(privilege_id) REFERENCES PRIVILEGES(id),
   PRIMARY KEY(user_id,privilege_id)
);

INSERT INTO userprivilege VALUES(1,1);
INSERT INTO userprivilege VALUES(1,2);
INSERT INTO userprivilege VALUES(1,3);

对应数据库表,创建javabean:

Privileges.java:

package app.java.proxy.demo.bean;

public class Privileges {

	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}
Userinfo:

package app.java.proxy.demo.bean;

public class Userinfo {

	private int id;
	private String username;
	private String password;
	public int getId() {
		return id;
	}
	public void setId(int 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;
	}
	
}


dao:

OperateDao:

package app.java.proxy.demo.dao;

import java.util.List;

import app.java.proxy.demo.bean.Privileges;

public interface OperateDao {

	public List<Privileges> findPrivileges(int id);

}


UserDao:

package app.java.proxy.demo.dao;

import app.java.proxy.demo.bean.Userinfo;

public interface UserDao {

	public Userinfo findUser(Userinfo userinfo);

}
dao.impl:

OperateDaoImpl:

package app.java.proxy.demo.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 app.java.proxy.demo.bean.Privileges;
import app.java.proxy.demo.bean.Userinfo;
import app.java.proxy.demo.dao.OperateDao;
import app.java.proxy.demo.utils.JDBCUtils;

public class OperateDaoImpl implements OperateDao {

	@Override
	public List<Privileges> findPrivileges(int id) {
		try {
			QueryRunner runner = new QueryRunner(JDBCUtils.getDataSource());
			String sql = "SELECT * FROM userprivilege WHERE user_id=?";
			List<Privileges> privileges = runner.query(sql, new BeanListHandler<Privileges>(Privileges.class), id);
			return privileges;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

}

UserDaoImpl:

package app.java.proxy.demo.dao.impl;

import java.sql.SQLException;

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

import app.java.proxy.demo.bean.Userinfo;
import app.java.proxy.demo.dao.UserDao;
import app.java.proxy.demo.utils.JDBCUtils;

public class UserDaoImpl implements UserDao {

	@Override
	public Userinfo findUser(Userinfo userinfo) {
		try {
			QueryRunner runner = new QueryRunner(JDBCUtils.getDataSource());
			String sql = "SELECT * FROM userinfo WHERE username=? AND password=?";
			Userinfo newUserinfo = runner.query(sql, new BeanHandler<Userinfo>(Userinfo.class), userinfo.getUsername(), userinfo.getPassword());
			return newUserinfo;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

}

service:

OperateService:

package app.java.proxy.demo.service;

import java.util.List;

import app.java.proxy.demo.bean.Privileges;
import app.java.proxy.demo.bean.Userinfo;
import app.java.proxy.demo.utils.Privilegeinfo;

public interface OperateService {

	public List<Privileges> findPrivilege(int id);

	@Privilegeinfo("添加图书")
	public String addBook(Userinfo userinfo);

	@Privilegeinfo("修改图书")
	public String editBook(Userinfo userinfo);

	@Privilegeinfo("查看图书")
	public String lookBook(Userinfo userinfo);

	@Privilegeinfo("删除图书")
	public String delBook(Userinfo userinfo);

}

UserService:

package app.java.proxy.demo.service;

import app.java.proxy.demo.bean.Userinfo;

public interface UserService {

	public Userinfo userLogin(Userinfo userinfo);

}

service.impl:

OperateServiceImpl:

package app.java.proxy.demo.service.impl;

import java.util.List;

import app.java.proxy.demo.bean.Privileges;
import app.java.proxy.demo.bean.Userinfo;
import app.java.proxy.demo.dao.OperateDao;
import app.java.proxy.demo.dao.impl.OperateDaoImpl;
import app.java.proxy.demo.service.OperateService;
import app.java.proxy.demo.utils.Privilegeinfo;

public class OperateServiceImpl implements OperateService {

	@Override
	public List<Privileges> findPrivilege(int id) {
		OperateDao operateDao = new OperateDaoImpl();
		List<Privileges> privileges = operateDao.findPrivileges(id);
		return privileges;
	}

	@Override
	public String addBook(Userinfo userinfo) {
		return null;
	}

	@Override
	public String editBook(Userinfo userinfo) {
		return null;
	}

	@Override
	public String lookBook(Userinfo userinfo) {
		return null;
	}

	@Override
	public String delBook(Userinfo userinfo) {
		return null;
	}

}


UserServiceImpl:

package app.java.proxy.demo.service.impl;

import app.java.proxy.demo.bean.Userinfo;
import app.java.proxy.demo.dao.UserDao;
import app.java.proxy.demo.dao.impl.UserDaoImpl;
import app.java.proxy.demo.service.UserService;

public class UserServiceImpl implements UserService {

	@Override
	public Userinfo userLogin(Userinfo userinfo) {
		UserDao userDao = new UserDaoImpl();
		Userinfo newUserinfo = userDao.findUser(userinfo);
		return newUserinfo;
	}

}

servlet:

BookServlet:

package app.java.proxy.demo.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import app.java.proxy.demo.bean.Privileges;
import app.java.proxy.demo.bean.Userinfo;
import app.java.proxy.demo.service.OperateService;
import app.java.proxy.demo.service.impl.OperateServiceImpl;
import app.java.proxy.demo.utils.ServiceFactory;

public class BookServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		//1 获取请求的参数:是什么操作
		String operate = request.getParameter("operate");
		
		//2 获取当前用户的信息  ,从中得到用户的id,根据id可以从用户权限表(关系表)中得到用户的权限
		Userinfo userinfo = (Userinfo) request.getSession().getAttribute("user");
		
		OperateService service = ServiceFactory.getOperateService(userinfo);
		String result = null;
		//3 判断用户是什么操作  查询数据库的userprivilege表,得到用户具有什么权限
		if(operate.equals("add")){
			result = service.addBook(userinfo);  //根据userinfo中的id得到权限表的Id,从而得到用户具备的权限
			if(result.equals("success")){
				// 说明具有权限
				request.getRequestDispatcher("/add.jsp").forward(request, response);
			}else{
				// 说明没有权限
				request.setAttribute("error_msg", "对不起,你没有添加书籍的权限!");
				request.getRequestDispatcher("/error.jsp").forward(request, response);
			}
		}else if(operate.equals("edit")){
			result = service.editBook(userinfo);
			if(result.equals("success")){
				// 说明具有权限
				request.getRequestDispatcher("/edit.jsp").forward(request, response);
			}else{
				// 说明没有权限
				request.setAttribute("error_msg", "对不起,你没有修改书籍的权限!");
				request.getRequestDispatcher("/error.jsp").forward(request, response);
			}
		}else if(operate.equals("look")){
			result = service.lookBook(userinfo);
			if(result.equals("success")){
				// 说明具有权限
				request.getRequestDispatcher("/look.jsp").forward(request, response);
			}else{
				// 说明没有权限
				request.setAttribute("error_msg", "对不起,你没有查看书籍的权限!");
				request.getRequestDispatcher("/error.jsp").forward(request, response);
			}
		}else if(operate.equals("delete")){
			result = service.delBook(userinfo);
			if(result.equals("success")){
				// 说明具有权限
				request.getRequestDispatcher("/delete.jsp").forward(request, response);
			}else{
				// 说明没有权限
				request.setAttribute("error_msg", "对不起,你没有删除书籍的权限!");
				request.getRequestDispatcher("/error.jsp").forward(request, response);
			}
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}


LoginServlet:

package app.java.proxy.demo.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import com.mchange.v2.codegen.bean.BeangenUtils;

import app.java.proxy.demo.bean.Userinfo;
import app.java.proxy.demo.service.UserService;
import app.java.proxy.demo.service.impl.UserServiceImpl;

public class LoginServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		try {
			Userinfo userinfo = new Userinfo();
			BeanUtils.populate(userinfo, request.getParameterMap());
			
			UserService service = new UserServiceImpl();
			Userinfo newUserinfo = service.userLogin(userinfo);
			
			if(newUserinfo == null){
				// 说明登录失败
				request.setAttribute("error_msg", "你的用户名或密码错误.");
				request.getRequestDispatcher("/login.jsp").forward(request, response);
			}else{
				// 说明登录成功
				request.getSession().setAttribute("user", newUserinfo);
				request.getRequestDispatcher("/index.jsp").forward(request, response);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

utils:

JDBCUtils:

package app.java.proxy.demo.utils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 * JDBC工具类
 * @author 金云龙
 * 
 */
public class JDBCUtils {
	private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	public static DataSource getDataSource() {
		return dataSource;
	}
	
	/*private static Properties props = new Properties();
	// static中的语句只执行一次,在当前类被加载时执行.
	static {
		try {
			
			 * 1 将配置文件中的内容加载到props对象中
			 
			// 获取类路径下的资源
			InputStream in = JDBCUtils.class.getResourceAsStream("/dbconfig.properties");
			// 加载配置文件
			props.load(in);
			
			 * 2 注册驱动类
			 
			Class.forName(props.getProperty("driverClassName"));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}*/

	/**
	 * 获取连接对象
	 * 
	 * @return
	 * @throws Exception
	 */
	public static Connection getConnection() throws Exception {
		/*
		 * 3 获取连接对象
		 */
		/*Connection conn = DriverManager.getConnection(props.getProperty("url"),
				props.getProperty("username"), props.getProperty("password"));*/
		
		return dataSource.getConnection();
	}
	
	public static void close(Statement stmt, Connection conn){
		if (stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}

		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
	
	public static void close(Statement stmt, Connection conn, ResultSet rs){
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}

		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}

}


Privilegeinfo:

package app.java.proxy.demo.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 当前注解用于配置用户的权限信息.
 *  * @Inherited注解:
 *    * 指示注释类型被自动继承。
 *    * 如果将该注解定义在接口的方法中,自动同步到该接口的实现类中.
 * @author JYL
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Privilegeinfo {

	String value();
	
}


ServiceFactory:

package app.java.proxy.demo.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ColumnListHandler;

import com.sun.org.apache.bcel.internal.generic.NEW;

import app.java.proxy.demo.bean.Userinfo;
import app.java.proxy.demo.service.OperateService;
import app.java.proxy.demo.service.impl.OperateServiceImpl;

/**
 * 该业务工厂类用于利用动态代理技术读取当前用户是否具有对应的业务权限.
 * 
 * @author JYL
 */
public class ServiceFactory {
	/**
	 * 该方法用于利用动态代理读取权限.
	 * 
	 * @return
	 */
	public static OperateService getOperateService(final Userinfo userinfo){
		
		OperateService proxyService = (OperateService) Proxy.newProxyInstance(OperateService.class.getClassLoader(), OperateServiceImpl.class.getInterfaces(), new InvocationHandler() {
			
			/**
			 * invoke()方法用于通过反射技术读取对应业务方法的权限信息. (通过反射读取注解,通过注解取得对应业务方法的权限信息)
			 */
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				
				//读取注解
				Privilegeinfo privilege = method.getAnnotation(Privilegeinfo.class);//传入注解的类型
				
				//1. 获取对应业务方法的权限信息(每个方法上的注解的信息:添加、修改、查看、删除图书)
				String privilegeinfo = privilege.value();
				
				//2. 获取当前用户的权限信息(查询数据库表(userprivilege,还要关联privilege表,才能获得权限信息),这里需要用户user_id信息)
				QueryRunner runner = new QueryRunner(JDBCUtils.getDataSource());
				//把userprivilege表和privilege表关联到一起
				String sql = "SELECT PRIVILEGES.name FROM userprivilege,PRIVILEGES WHERE userprivilege.privilege_id = PRIVILEGES.id AND userprivilege.user_id=?";
				List<String> privileges = runner.query(sql, new ColumnListHandler<String>("name"), userinfo.getId());
				
				//3. 判断当前用户是否具有对应的权限信息
				for (String privilegeValue : privileges) {
					if(privilegeinfo.equals(privilegeValue)){
						// 如果具有
						return "success";
					}
				}
				// 如果没有
				return "error";
			}
		});
		return proxyService;
	}
}


c3p0-config:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/day0110</property>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="user">root</property>
		<property name="password">root</property>
		<property name="acquireIncrement">3</property>
		<property name="initialPoolSize">10</property>
		<property name="minPoolSize">2</property>
		<property name="maxPoolSize">10</property>
	</default-config>
</c3p0-config>

add:

<body>
    <h1>添加书籍成功!   <a href="index.jsp">返回</a></h1>
  </body>

delete:

<body>
    <h1>删除书籍成功!   <a href="index.jsp">返回</a></h1>
  </body>

upload:

<body>
    <form action="upload" method="post" enctype="multipart/form-data">
    	<input type="text" name="filetext"><br>
    	<input type="file" name="upload"><br>
    	<input type="submit" value="上传">
    </form>
  </body>

look:

 <body>
    <h1>查看书籍成功!   <a href="index.jsp">返回</a></h1>
  </body>

edit:

 <body>
    <h1>修改书籍成功!   <a href="index.jsp">返回</a></h1>
  </body>

error:

<body>
    <h1>${error_msg }</h1>
  </body>

index:

<body>
    <c:if test="${empty user }">
    	<h1><a href="login.jsp">请先去登录</a></h1>
    </c:if>
    <c:if test="${not empty user }">
    	<h1>欢迎您,${user.username }</h1>
    	
    	<h1>以下是功能列表</h1>
    	<h3><a href="book?operate=add">添加书籍</a></h3>
    	<h3><a href="book?operate=edit">修改书籍</a></h3>
    	<h3><a href="book?operate=look">查看书籍</a></h3>
    	<h3><a href="book?operate=delete">删除书籍</a></h3>
    	
    </c:if>
  </body>

login:

<body>
    <form action="login" method="post">
    	用户名:<input type="text" name="username"><br>
    	密码:<input type="password" name="password"><br>
    	<input type="submit" value="登录">
    </form>
  </body>