RBAC 是当下权限系统的设计基础,同时有两种解释:
一: Role-Based Access Control,基于角色的访问控制
即,你要能够删除产品,那么当前用户就必须拥有产品经理这个角色
二:Resource-Based Access Control,基于资源的访问控制
即,你要能够删除产品,那么当前用户就必须拥有删除产品这样的权限
Shrio
shrio两种登录方式:1、读取shrio.ini配置文件 2、使用 DatabaseRealm(数据库连接比较)
MD5加密的时候:使用传入密码需要加密、插入语句需要加密,DatabaseRealm需要加密.
package com.company;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.Set;
public class DatabaseRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//能进入到这里,表示账号已经通过验证了
String userName =(String) principalCollection.getPrimaryPrincipal();
//通过DAO获取角色和权限
Set<String> permissions = new UserDao().listPermissions(userName);
Set<String> roles = new UserDao().listRoles(userName);
//授权对象
SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();
//把通过DAO获取到的角色和权限放进去
s.setStringPermissions(permissions);
s.setRoles(roles);
return s;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取账号密码
UsernamePasswordToken t = (UsernamePasswordToken) token;
String userName= token.getPrincipal().toString();
String password =new String(t.getPassword());
//获取数据库中的密码
User user = new UserDao().getUser(userName);
String passwordInDB = user.getPassword();
String salt = user.getSalt();
String passwordEncoded = new SimpleHash("md5",password,salt,2).toString();
if(null==user || !passwordEncoded.equals(passwordInDB))
throw new AuthenticationException();
//认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm
SimpleAuthenticationInfo a = new SimpleAuthenticationInfo(userName,password,getName());
return a;
}
}
UserDao.java
package com.company;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import java.sql.*;
import java.util.HashSet;
import java.util.Set;
/**
* @ProjectName: UserDao
* @Package: com.company
* @Description:
* @Author: huyuqiao
* @CreateDate: 2020/9/25 10:16
*/
public class UserDao {
public UserDao(){
try{
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e){
e.printStackTrace();
}
}
public Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false", "root", "root");
}
public String createUser(String name, String password) {
String sql = "insert into user values(null,?,?,?)";
String salt = new SecureRandomNumberGenerator().nextBytes().toString(); //盐量随机
String encodedPassword= new SimpleHash("md5",password,salt,2).toString();
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
ps.setString(1, name);
ps.setString(2, encodedPassword);
ps.setString(3, salt);
ps.execute();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
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 User getUser(String userName) {
User user = null;
String sql = "select * from user where name = ?";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
ps.setString(1, userName);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
user.setSalt(rs.getString("salt"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return user;
}
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) throws Throwable {
System.out.println(new UserDao().listRoles("zhang3"));
System.out.println(new UserDao().listRoles("li4"));
System.out.println(new UserDao().listPermissions("zhang3"));
System.out.println(new UserDao().listPermissions("li4"));
}
}
TestShiro.java
package com.company;
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.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import java.util.ArrayList;
import java.util.List;
/**
* @ProjectName: TestShiro
* @Package: com.company
* @Description:
* @Author: huyuqiao
* @CreateDate: 2020/9/25 9:35
*/
public class TestShiro {
public static void main(String[] args) {
new UserDao().createUser("tom", "123");
User user22 = new User();
user22.setName("tom");
user22.setPassword("123");
if(login(user22))
System.out.println("登录成功");
else
System.out.println("登录失败");
//用户们
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.setName("wang5");
wang5.setPassword("wrongpassword");
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 permitAddProduct = "addProduct";
String permitAddOrder = "addOrder";
List<String> permits = new ArrayList<>();
permits.add(permitAddProduct);
permits.add(permitAddOrder);
//登陆每个用户
for (User user : users) {
if(login(user))
System.out.printf("%s 成功登陆,用的密码是 %s %n",user.getName(),user.getPassword());
else
System.out.printf("%s 成功失败,用的密码是 %s %n",user.getName(),user.getPassword());
}
System.out.println("-------how2j 分割线------");
//判断能够登录的用户是否拥有某个角色
for (User user : users) {
for (String role : roles) {
if(login(user)) {
if(hasRole(user, role))
System.out.printf("%s 拥有角色: %s %n",user.getName(),role);
else
System.out.printf("%s 不拥有角色: %s %n",user.getName(),role);
}
}
}
System.out.println("-------how2j 分割线------");
//判断能够登录的用户,是否拥有某种权限
for (User user : users) {
for (String permit : permits) {
if(login(user)) {
if(isPermitted(user, permit))
System.out.printf("%s 拥有权限: %s %n",user.getName(),permit);
else
System.out.printf("%s 不拥有权限: %s %n",user.getName(),permit);
}
}
}
}
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 Subject getSubject(User user) {
//加载配置文件,并获取工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//获取安全管理者实例
SecurityManager sm = factory.getInstance();
//将安全管理者放入全局对象
SecurityUtils.setSecurityManager(sm);
//全局对象通过安全管理者生成Subject对象
Subject subject = SecurityUtils.getSubject();
return subject;
}
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) {
//验证错误
return false;
}
return subject.isAuthenticated();
}
}