目录
1. 权限管理概述
基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源。
权限管理包括用户身份认证和授权两部分,简称认证授权。对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问。
RBAC(Role Based Access Control) :某个用户拥有什么角色,被允许做什么事情(权限)
用户登录—>分配角色---->(权限关联映射)---->鉴权(拥有什么什么权限)
2. 什么是shiro权限框架?
Apache Shiro 是一个强大且易用的 Java 安全框架
Shiro可以帮我们完成 :认证、授权、加密、会话管理、与 Web 集成、缓存等。
3. 核心组件
主要认识: Subject(用户): 当前的操作用户 获取当前用户
Subject currentUser = SecurityUtils.getSubject()
Subject主体,外部应用与subject进行交互,subject将用户作为当前操作的主体,这个主体:可以是一个通过浏览器请求的用户,也可能是一个运行的程序。Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权
SecurityManager(安全管理器):Shiro的核心,负责与其他组件进行交互,实现 subject 委托的各种功能
SecurityManager权限管理器,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口
Realms(数据源) :Realm会查找相关数据源,充当与安全管理间的桥梁,经过Realm找到数据源进行认证,授权等操作
Realm领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据 比如: 如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。 注意: 不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。
Authenticator(认证器): 用于认证,从 Realm 数据源取得数据之后进行执行认证流程处理。
Authenticator即认证器,对用户登录时进行身份认证
Authorizer(授权器):用户访问控制授权,决定用户是否拥有执行指定操作的权限。
Authorizer授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。
SessionManager (会话管理器):支持会话管理
SessionManager会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。
CacheManager (缓存管理器):用于缓存认证授权信息
CacheManager缓存管理,将用户权限数据存储在缓存,这样可以提高性能
Cryptography(加密组件):提供了加密解密的工具包
Cryptography密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、md5等功能
4. 快速入门(使用ini文件认证)
(1)创建java的maven工程并引入shiro依赖
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies>
(2)创建一个ini文件
# [users]定义用户的信息--当对于表名叫users
[users]
# =左边表示用户名 =右边表示密码
zhangsan=123456
lisi=123456
(3)代码实现:
public class Test1 {
public static void main(String[] args) {
//1. 创建 SecurityManager 对象
DefaultSecurityManager manager = new DefaultSecurityManager();
//2. 设置使用 realm 读取 shiro.ini文件信息
IniRealm realm = new IniRealm("classpath:shiro.ini");
manager.setRealm(realm);
//3. 放入上下文 使其生效
SecurityUtils.setSecurityManager(manager);
//4. 获取 Subject
Subject subject = SecurityUtils.getSubject();
//5. 调用认证方法
//5.1 用户信息封装到 UsernamePasswordToken中
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123456");
//5.2 进行认证
try {
subject.login(token);
System.out.println("登录认证成功√√√√√√√√√√√√");
} catch (Exception e) {
e.printStackTrace();
System.out.println("失败~~~~~~~~~~~");
}
}
}
(4)认证流程图:
5. 认证后进行授权(使用ini文件)
(1)修改ini文件
# 定义用户信息--->等于表名叫 users
[users]
# 用户名 = 密码 & 对应的角色信息
wjq=123456,admin,people
lisi=123456,people,person
# 定义角色信息 及 对应的权限信息
[roles]
admin=user::query,user::insert,user::delete,user::update
people=user::query
person=user::delete,user::update
(2)代码实现:
//1. 获取 securityManager
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//创建realm
IniRealm realm = new IniRealm("classpath:shiro.ini");
//2. 指定realm
securityManager.setRealm(realm);
//3. 使其上下文生效
SecurityUtils.setSecurityManager(securityManager);
//4. 获取Subject
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("wjq", "123456");
try {
subject.login(token);
System.out.println("登陆成功");
} catch (AuthenticationException e) {
throw new RuntimeException(e);
}
// subject.logout();//用户退出
// System.out.println("退出登录-------");
System.out.println("====开始权限校验===");
boolean permitted = subject.isPermitted("user::query");
System.out.println("该用户是否具有user::query权限" + permitted);
boolean[] booleans = subject.isPermitted("user::query", "user::insert", "user::delete", "user::update");
System.out.println("当前用户是否这些权限" + Arrays.toString(booleans));
boolean permittedAll = subject.isPermittedAll("user::query", "user::insert");
System.out.println("同时具有user::query和user::insert权限?" + permittedAll);
流程图:
6. 用户认证和授权:自定义数据源
(1)创建一个MyRealm类继承AuthorizingRealm
public class MyRealm extends AuthorizingRealm {
private UserService userService = new UserService();
/**
* 授权 doGetAuthorizationInfo
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("权限信息开始校验。。。。。。。。。。。。。。。");
//获取认证过的用户名
String username = (String) principalCollection.getPrimaryPrincipal();
//模拟查询数据库
Set<String> permission = userService.findPermissionByUserName(username);
//权限校验
if(permission.size() > 0) {
SimpleAuthorizationInfo permissionInfo = new SimpleAuthorizationInfo();
permissionInfo.addStringPermissions(permission);
return permissionInfo;
}
return null;
}
/**
* 认证 doGetAuthenticationInfo
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("开始进行用户认证............");
//1.获取用户名 即登录用户的账号
String username = (String) authenticationToken.getPrincipal();
//2.根据用户名查询数据库
User user = userService.findByUserName(username);
//3.进行用户信息的认证
if (user != null){
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,user.getPassword(),this.getName());
//认证成功后返回 AuthenticationInfo
return info;
}
return null;
}
}
(2)main测试类
//1. 获取 securityManager
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//创建realm
MyRealm myRealm = new MyRealm();
//2. 指定realm
securityManager.setRealm(myRealm);
//3. 使其上下文生效
SecurityUtils.setSecurityManager(securityManager);
//4. 获取Subject
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("wjq", "123456");
try {
subject.login(token);
System.out.println("登陆成功-----------");
} catch (Exception e) {
//e.printStackTrace();
System.out.println("登录失败。。。。。。。");
}
System.out.println(subject.isPermitted("user::query"));
System.out.println(subject.isPermitted("user::export"));
(3)UserService
public class UserService {
public User findByUserName(String username) {
if("wjq".equals(username)){
return new User(1,"wjq","123456","王俊奇");
} else if ("lisi".equals(username)) {
return new User(2,"lisi","123456","李四");
}
return null;
}
public Set<String> findPermissionByUserName(String username) {
Set<String> list = new HashSet<>();
if("wjq".equals(username)){
list.add("user::query");
list.add("user::delete");
list.add("user::update");
list.add("user::insert");
} else if ("lisi".equals(username)) {
list.add("user::export");
}
return list;
}
}
(4)User实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
//用户真实姓名
private String realName;
}