Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
1. 粗粒度 URL 级别权限控制
可以基于 Filter 实现 在数据库中存放 用户、权限、访问 URL 对应关系, 当前用户访问一个 URL 地址,查 询数据库判断用户当前具有权限,是否包含这个 URL,如果包含允许访问,如果不包含 权 限不足 !!!
2. 细粒度方法级别权限控制
可以代理、自定义注解实现, 访问目标对象方法,在方法上添加权限注解信息,对目 标对象创建代理对象,访问真实对象先访问代理对象,在代理对象查询数据库判断是否具有 注解上描述需要权限,具有权限 允许访问,不具有权限,拦截访问,提示权限不足
1.1. Shiro 运行主要运行流程
ApplicationCode 用户编写代码
Subject 就是 shiro 管理的用户
SecurityManager 安全管理器,是 shiro 权限控制核心对象, 在编程时,只需要操作 Subject 方法, 底层调用 SecurityManager 方法,无需直接编程操作 SecurityManager
Realm 应用程序和安全数据之间连接器 ,应用程序 进行权限控制读取安全数据(数据 表、文件、网路 … ),通过 Realm 对象完成
登录流程: 应用程序 --- Subject --- SecurityManager --- Realm --- 安全数据
1.2. Shiro 进行权限控制
四种主要方式 :
1、 在程序中 通过 Subject 编程方式进行权限控制
2、 配置 Filter 实现 URL 级别粗粒度权限控制
3、 配置代理,基于注解实现细粒度权限控制
4、 在页面中使用 shiro 自定义标签实现 页面显示权限控制
配置 shiro 的 Filter 实现 URL 级别权限控制
1、 配置 web.xml
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
shiroFilter
/*
2、 配置 applicationContext-shiro.xml
/login.html* = anon
/user_login.action* = anon
/validatecode.jsp* = anon
/css/** = anon
/js/** = anon
/images/** = anon
/services/** = anon
/pages/base/courier.html* = perms[courier:list]
/pages/base/area.html* = roles[base]
/** = authc
参考:
1、 填写表单
2、 编写 UserAction 提供 login 登录方法
public String login() {
// 用户名和密码 都保存在model中
// 基于shiro实现登录
Subject subject = SecurityUtils.getSubject();
// 用户名和密码信息
AuthenticationToken token = new UsernamePasswordToken(
model.getUsername(), model.getPassword());
try {
subject.login(token);
// 登录成功
// 将用户信息 保存到 Session
return SUCCESS;
} catch (AuthenticationException e) {
// 登录失败
e.printStackTrace();
return LOGIN;
}
}
3、 自定义 Realm 对象,实现认证方法 自定义 Realm 实现 Realm 接口 (实际开发中,只需要继承 AuthorizingRealm )
// 认证...
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
System.out.println("shiro 认证管理... ");
// 转换token
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
// 根据用户名 查询 用户信息
User user = userService.findByUsername(usernamePasswordToken
.getUsername());
if (user == null) {
// 用户名不存在
// 参数一: 期望登录后,保存在Subject中信息
// 参数二: 如果返回为null 说明用户不存在,报用户名
// 参数三 :realm名称
return null;
} else {
// 用户名存在
// 当返回用户密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
// 如果密码一致 登录成功, 如果密码不一致 报密码错误异常
return new SimpleAuthenticationInfo(user, user.getPassword(),
getName());
}
}
}
参考
实现 Realm 的授权方法
// 授权...
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
System.out.println("shiro 授权管理...");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 根据当前登录用户 查询对应角色和权限
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
// 调用业务层,查询角色
List roles = roleService.findByUser(user);
for (Role role : roles) {
authorizationInfo.addRole(role.getKeyword());
}
// 调用业务层,查询权限
List permissions = permissionService.findByUser(user);
for (Permission permission : permissions) {
authorizationInfo.addStringPermission(permission.getKeyword());
}
return authorizationInfo;
}
细粒度(方法)权限控制原因: 自定义注解(加在方法上,在注解中描述需要权限信 息),对目标业务对象创建代理对象,在代理方法中使用反射技术读取注解信息,获取需要 权限,查询当前登录用户具有权限是否满足
1、 配置 applicationContext-shiro.xml 激活注解
针对 CourierServiceImpl 对象进行代理
使用方法注解进行权限控制, 当权限不足时,代理对象抛出一个异常 org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [courier_add]
第一种:URL 级别粗粒度权限控制 配置 web.xml 的 shiroFilter 拦截 /* 在 spring 的 applicationContext*.xml 配置文件中配置同名 bean,配置 filterChainDefinitions 拦截控制规则
xxx.html* = anon (未登录可以访问)
xxx.html* =authc (必须登录才能访问 )
xxx.html* = perms[权限] (需要特定权限才能访问)
xxx.html* = roles[角色] (需要特定角色才能访问 )
第二种: 方法级别细粒度权限控制 在 spring 的 applicationContext*.xml 配置 spring aop 对 spring 管理 bean 对象开启 shiro 注解支持
@RequiresPermissions(权限) 需要特定权限才能访问
@RequiresRoles(角色) 需要特定角色才能访问
@RequiresAuthentication 需要认证才能访问
第三种:通过 shiro 自定义标签,实现页面元素显示控制