shiro(三)数据库

RBAC 概念

RBAC 是当下权限系统的设计基础,同时有两种解释:
一: Role-Based Access Control,基于角色的访问控制
即,你要能够删除产品,那么当前用户就必须拥有产品经理这个角色
二:Resource-Based Access Control,基于资源的访问控制
即,你要能够删除产品,那么当前用户就必须拥有删除产品这样的权限

 用户,角色,权限, 以及 2 张中间表来建立 用户与角色的多对多关系,角色与权限的多对多关系。 用户与权限之间也是多对多关系,但是是通过 角色间接建立的。

多对多:

一个用户可以有多种角色,一个角色也可以赋予多个用户。 
一个角色可以包含多种权限,一种权限也可以赋予多个角色。

DROP DATABASE IF EXISTS shiro;
CREATE DATABASE shiro DEFAULT CHARACTER SET utf8;
USE shiro;
 
drop table if exists user;
drop table if exists role;
drop table if exists permission;
drop table if exists user_role;
drop table if exists role_permission;
 
create table user (
  id bigint auto_increment,
  name varchar(100),
  password varchar(100),
  constraint pk_users primary key(id)
) charset=utf8 ENGINE=InnoDB;
 
create table role (
  id bigint auto_increment,
  name varchar(100),
  constraint pk_roles primary key(id)
) charset=utf8 ENGINE=InnoDB;
 
create table permission (
  id bigint auto_increment,
  name varchar(100),
  constraint pk_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB;
 
create table user_role (
  uid bigint,
  rid bigint,
  constraint pk_users_roles primary key(uid, rid)
) charset=utf8 ENGINE=InnoDB;
 
create table role_permission (
  rid bigint,
  pid bigint,
  constraint pk_roles_permissions primary key(rid, pid)
) charset=utf8 ENGINE=InnoDB;
INSERT INTO `permission` VALUES (1,'addProduct');
INSERT INTO `permission` VALUES (2,'deleteProduct');
INSERT INTO `permission` VALUES (3,'editProduct');
INSERT INTO `permission` VALUES (4,'updateProduct');
INSERT INTO `permission` VALUES (5,'listProduct');
INSERT INTO `permission` VALUES (6,'addOrder');
INSERT INTO `permission` VALUES (7,'deleteOrder');
INSERT INTO `permission` VALUES (8,'editOrder');
INSERT INTO `permission` VALUES (9,'updateOrder');
INSERT INTO `permission` VALUES (10,'listOrder');
INSERT INTO `role` VALUES (1,'admin');
INSERT INTO `role` VALUES (2,'productManager');
INSERT INTO `role` VALUES (3,'orderManager');
INSERT INTO `role_permission` VALUES (1,1);
INSERT INTO `role_permission` VALUES (1,2);
INSERT INTO `role_permission` VALUES (1,3);
INSERT INTO `role_permission` VALUES (1,4);
INSERT INTO `role_permission` VALUES (1,5);
INSERT INTO `role_permission` VALUES (1,6);
INSERT INTO `role_permission` VALUES (1,7);
INSERT INTO `role_permission` VALUES (1,8);
INSERT INTO `role_permission` VALUES (1,9);
INSERT INTO `role_permission` VALUES (1,10);
INSERT INTO `role_permission` VALUES (2,1);
INSERT INTO `role_permission` VALUES (2,2);
INSERT INTO `role_permission` VALUES (2,3);
INSERT INTO `role_permission` VALUES (2,4);
INSERT INTO `role_permission` VALUES (2,5);
INSERT INTO `role_permission` VALUES (3,6);
INSERT INTO `role_permission` VALUES (3,7);
INSERT INTO `role_permission` VALUES (3,8);
INSERT INTO `role_permission` VALUES (3,9);
INSERT INTO `role_permission` VALUES (3,10);
INSERT INTO `user` VALUES (1,'zhang3','12345');
INSERT INTO `user` VALUES (2,'li4','abcde');
INSERT INTO `user_role` VALUES (1,1);
INSERT INTO `user_role` VALUES (2,2);

等同于

#定义安全相关的数据
#用户
[users]
zhang3 =12345,admin

li4=abcde,productManager
#角色和权限
[roles]
#admin什么都能做
admin=*
#productManager做Product相关
productManager = addProduct,deleteProduct,updateProduct,selectProduct
#orderManager做Product相关
orderManager = addOrder,deleteOrder,updateOrder,selectOrder

User类 

private int id;
	 	private String name;
	    private String password;
	    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;
	    }
	    public String getPassword() {
	        return password;
	    }
	    public void setPassword(String password) {
	        this.password = password;
	    }
		public User(String name, String password) {
			super();
			this.name = name;
			this.password = password;
		}
		public User() {
			super();
		}

Dao提供三个方法

1.获得密码

2.根据用户名查询此用户有哪些角色

3.根据用户名查询此用户有哪些权限,这是5张表的关联

package dao_shiro;

import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.sql.Connection;
/**
 * shiro数据库实现
 * @author cxy
 *
 */
public class Dao {
	public  Dao() {
	try {
		Class.forName("com.mysql.jdbc.Driver");
	}catch(ClassNotFoundException e) {
		e.printStackTrace();
	}
	}
	
	public Connection getConnection() throws SQLException {
		Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=UTF-8", "root",
            "root");
		return c;
	}
	//根据用户名查密码,既验证也检查用户是否存在,一举两得
	 public String getPassword(String userName) {
	        String sql = "select password from user where name = ?";
	        try (Connection c = getConnection(); 
	        	PreparedStatement ps = c.prepareStatement(sql);
	        		) {
	             
	            ps.setString(1, userName);
	             
	            ResultSet rs = ps.executeQuery();
	 
	            if (rs.next())
	                return rs.getString("password");
	 
	        } catch (SQLException e) {
	 
	            e.printStackTrace();
	        }
	        return null;
	    }
	 
	 
	//根据用户名查有哪些角色,
		 public Set<String> listRoles(String userName) {
			 Set<String> roles = new HashSet<>();
		        String sql = "select r.name from user u "
		        		+ "LEFT JOIN user_role ur on u.id = ur.uid "
		        		+ "LEFT JOIN role r on r.id = ur.rid "
		        		+ "WHERE u.name=  ?";
		        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
		            ps.setString(1, userName);
		            ResultSet rs = ps.executeQuery();
		             
		            while (rs.next()) {
		                roles.add(rs.getString(1));
		            }
		             
		        } catch (SQLException e) {
		             
		            e.printStackTrace();
		        }
		        return roles;
		    }
		 //根据用户名查用户有哪些权限
		 public Set<String> listPermissions(String userName) {
		        Set<String> permissions = new HashSet<>();
		        String sql =
		        "select p.name from user u "+
		        "left join user_role ru on u.id = ru.uid "+
		        "left join role r on r.id = ru.rid "+
		        "left join role_permission rp on r.id = rp.rid "+
		        "left join permission p on p.id = rp.pid "+
		        "where u.name =?";
		         
		        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
		             
		            ps.setString(1, userName);
		             
		            ResultSet rs = ps.executeQuery();
		             
		            while (rs.next()) {
		                permissions.add(rs.getString(1));
		            }
		             
		        } catch (SQLException e) {
		             
		            e.printStackTrace();
		        }
		        return permissions;
		    }
		 
		 public static void main(String[] args) {
			System.out.println(new Dao().getPassword("zhang3"));
			System.out.println(new Dao().getPassword("li4"));
			System.out.println(new Dao().listRoles("zhang3"));
			System.out.println(new Dao().listRoles("li4"));
			System.out.println(new Dao().listPermissions("zhang3"));
			System.out.println(new Dao().listPermissions("li4"));
		}
	 
}

Realm 

就是个中介。 Realm 得到了 Shiro 给的用户和密码后,有可能去找 ini 文件,就像Shiro 入门中的 shiro.ini,也可以去找数据库,就如同本知识点中的 DAO 查询信息。

Realm 就是干这个用的,它才是真正进行用户认证和授权的关键地方。

AuthorizingRealm

doGetAuthenticationInfo()  验证

doGetAuthorizationInfo()  授权

package dao_shiro;

import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class DataBaseRealm extends AuthorizingRealm {

	@Override
	//授权
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		//通过验证
		String userName = (String) principalCollection.getPrimaryPrincipal();
		Set<String> listRoles = new Dao().listRoles(userName);
		Set<String> listPermissions = new Dao().listPermissions(userName);
		
		//授权对象
		 SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();
		 s.setRoles(listRoles);
		 s.setStringPermissions(listPermissions);
		return s;
	}

	@Override
	//验证
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//获取用户和密码
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
		String userName = token.getPrincipal().toString();
		String password = new String(usernamePasswordToken.getPassword());

		//数据库取得密码
		String passworddb = new Dao().getPassword(userName);
		//如果为空就是账号不存在,如果不相同就是密码错误,但是都抛出父类AuthenticationException,
		//而不是抛出具体错误原因,免得给破解者提供帮助信息
		if(null==passworddb&&!passworddb.equals(password)) {
			throw new AuthenticationException();
		}//认证信息里存放账号密码, getName() 返回当前类名 :databaseRealm
        SimpleAuthenticationInfo a = new SimpleAuthenticationInfo(userName,password,getName());
        return a;
		
	}
	
}

 Shiro 怎么找到这个 Realm 呢? 那么就需要下一步,修改ini,    shiro-dao.ini,

在配置文件里,就指定当前的realm 是databaseRealm 。因为 默认情况下是找 IniRealm。

[main]
databaseRealm=dao_shiro.DataBaseRealm
securityManager.realms=$databaseRealm

Test,修改ini的名字

package dao_shiro;

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

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

import ini_shiro.User;

import org.apache.shiro.mgt.SecurityManager;
public class Test {
public static void main(String[] args) {
	/**
	 * 准备三个用户,两个定义了,一个没有
	 */
	User zhang3 = new User();
	zhang3.setName("zhang3");
    zhang3.setPassword("12345");
    
    User li4 = new User();
    li4.setName("li4");
    li4.setPassword("abcde");
    
    User wang5 = new User("wang5","wrong");//没有定义在shiro.ini中
    
    List<User> users = new ArrayList<>();
    users.add(zhang3);
    users.add(li4);
    users.add(wang5);
    
    //定义角色
    String roleAdmin = "admin";
    String roleProductManager ="productManager"; 
    List<String> roles = new ArrayList<>();
    roles.add(roleAdmin);
    roles.add(roleProductManager);
    
    
    //定义权限
    String permitProduct = "addProduct"; 
    String permitOrder = "addOrder"; 
    List<String> permits = new ArrayList<>();
    permits.add(permitProduct);
    permits.add(permitOrder);
    
    //登陆每个用户
    for (User user : users) {
        if(login(user))
            System.out.printf("%s \t登陆成功,用的密码是 %s\t %n",user.getName(),user.getPassword());
        else
            System.out.printf("%s \t登录失败,用的密码是 %s\t %n",user.getName(),user.getPassword());
    }
     
    System.out.println("----分割线------");
     
    //判断能够登录的用户是否拥有某个角色
    for (User user : users) {
        for (String role : roles) {
            if(login(user)) {
                if(hasRole(user, role))
                    System.out.printf("%s\t 拥有角色: %s\t%n",user.getName(),role);
                else
                    System.out.printf("%s\t 不拥有角色: %s\t%n",user.getName(),role);
            }
        }  
    }
    System.out.println("------ 分割线------");

    //判断能够登录的用户,是否拥有某种权限
   for(User user:users) {
	   for(String role:roles) {
		   for(String permit:permits) {
			   if(login(user)) {
				   if(hasRole(user, role)) {
					   if(isPermitted(user, permit)) {
						   System.out.printf("%s\t 拥有权限:%s\t%n ",user.getName(),permit);
					   }
					   else
						   System.out.printf("%s\t 没有权限:%s \t%n ",user.getName(),permit);
				   }
			   }
		   }
	   }
   }
}

//获取当前用户
private static Subject getSubject(User user) {
    //加载配置文件,并获取工厂
    Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-dao.ini");
    //获取安全管理者实例
    SecurityManager sm = factory.getInstance();
    //将安全管理者放入全局对象
    SecurityUtils.setSecurityManager(sm);
    //全局对象通过安全管理者生成Subject对象
    Subject subject = SecurityUtils.getSubject();

    return subject;
}

//是否有角色
private static boolean hasRole(User user,String role) {
	Subject subject = getSubject(user);
	return subject.hasRole(role);
	}
//是否有权限
private static boolean isPermitted(User user,String permit) {
	Subject subject = getSubject(user);
	return subject.isPermitted(permit);
	}

private static boolean login(User user) {
	Subject subject = getSubject(user);
	if(subject.isAuthenticated()) {
		subject.logout();
	}
	UsernamePasswordToken token = new UsernamePasswordToken(user.getName(),user.getPassword());
	try {
		//将用户的数据token 最终传递到Realm中进行对比
		subject.login(token);	
	}catch(AuthenticationException e) {
		//e.printStackTrace();//验证错误
		return false;
	}
	
	return subject.isAuthenticated();//是否登录
}
}

猜你喜欢

转载自blog.csdn.net/qq_38930240/article/details/86608715
今日推荐