Shiro 框架
官方解释
中文:Apache Shiro是一个强大的并且简单使用的java权限框架。主要应用认证(Authentication),授权(Authorization),cryptography(加密),和Session Manager。Shiro具有简单易懂的API,使用Shiro可以快速并且简单的应用到任何应用中,无论是从最小的移动app到最大的企业级web应用都可以使用。
核心功能
1、Authentication 认证。如用户的登录。
2、Authorization 授权。用户是否有权限访问指定URL等。
3、Cryptography 密码学。如密码的加密。
4、Session Management Session 管理。
5、Web Integration Web集成。Shiro不依赖于容器。
基本概念
1、Subject:主体。每个用户登录成功后都会对应一个Subject对象,所有用户信息都存放在Subject中。
2、Security Manager:Shiro最大的容器,此容器中包含了Shiro的绝大多数功能。
3、Authenticator:认证器。执行认证过程调用的组件。里面包含了认证策略。
4、Authorizer:授权器。执行授权时调用的组件。
5、Session Manager:Shiro被Web集成后,HttpSession对象会由Shiro的Session Manager进行管理。
6、Cache Manager:缓存管理。Shiro执行很多第三方缓存技术。例如:EHCache等。
7、Session DAO操作Session内容的组件
8、Realms
Shiro框架实现权限控制不依赖于数据库,通过内置数据也可以实现权限控制。但是目前绝大多数应用的数据都存储在数据库中,所以Shiro提供了Realms组件,此组件的作用就是访问数据库。Shiro内置的访问数据库的代码,通过简单配置就可以访问数据库,也可以自定义Realms实现访问数据库逻辑。
配置文件
Shiro的全局配置文件就是.ini文件,ini中数据都是固定数据。(K-V存储)
1、[main] 主体部分-配置类对象,或设置属性等操作。出现$时才表示是引用对象
2、[users] 定义用户,密码及用户可以具有的角色。
3、[roles] 定义角色具有的权限。
4、[urls] 定义哪个控制器被哪个过滤器过滤.Shiro内置很多过滤器。
[urls]
控制器名称=过滤器名称
/login=authc
/=anon
5、内置过滤器
anon:不认证也可以访问。例如:/admin/=anon
authc:必须认证。
authcBasic:没有参数时表示httpBasic认证(客户端认证方式)。
logout:退出。
noSessionCreation:新增Filter,表示没有Session创建。
perms:判断是有具有指定权限。例如:/admin/user/**=perms[“per1”,”per2”]。必须同时具有给定权限才可以访问。如果只有一个权限可以省略双引号。
port:限制端口。例如:/admin/**=port[8081]。
rest:请求方式和权限的简便写法。例如:/admin/=rest[user]/admin/=perms[user:方式],方式是http请求的方式:post、get等。
roles:判断是否具有指定权限。/admin/**=roles[role1]
ssl:表示是安全的请求。协议为https
user:表示必须存在用户。
认证流程
1、获取主体,通过主体Subject对象的login方法进行登录,
2、把Subject中内容传递给Security Manager,
3、Security Manager内部组件Authenticator进行认证,
4、认证数据使用InI Realm,调用Ini文件中数据。
名词解释
1、Principal: 身份。用户名,邮箱,手机等能够唯一确认身份的信息.
2、Credential: 凭证,代表密码等。
3、AuthenticationInfo:认证时存储认证信息。
代码测试 - 自定义认证
public class TestMyRealm {
public static void main(String[] args) {
//1.获取SecurityManager的工厂对象
Factory<SecurityManager> factory =
new IniSecurityManagerFactory("classpath:shiro.ini");
//2.生产SecurityManager对象
SecurityManager securityManager = factory.getInstance();
//3.将生产的SecurityManager存储到SecurityUtils中,保证SecurityManager
// 在一次请求内的任意位置获取的是同一SecurityManager对象,而且不同的请求获取的不同
SecurityUtils.setSecurityManager(securityManager);
//4.获取subject对象去完成认证
Subject subject = SecurityUtils.getSubject();
//5.创建认证信息对象,存储认证数据
AuthenticationToken token = new UsernamePasswordToken("zhangsan", "zs");
//6.完成认证操作
try {
//login()方法没有返回值,只能通过是否有异常判断是否登录成功。
subject.login(token);
System.out.println("登录成功");
} catch (UnknownAccountException e) {
System.out.println("账号不存在");
} catch (IncorrectCredentialsException e) {
System.out.println("密码错误");
} catch (AuthenticationException e) {
e.printStackTrace();
}
}
}
public class MyRealm extends AuthenticatingRealm {
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//1.获取要认证的身份(唯一的)
String username = token.getPrincipal().toString();
//2.身份验证
if ("zhangsan".equals(username)){//假设用户名是从数据库中获取的
//3.身份验证通过后,验证凭证
String pwd = new String((char[]) token.getCredentials());//u哦农户在页面中书写的密码
String password="937592a4d4d967cdd0dc3431403813dc";//从数据库中查询的密码
//获取数据的id
Long id = 123L;
//4.验证密码
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
token.getPrincipal(), password, ByteSource.Util.bytes(id+""),"realmname");
return info;//验证通过返回
}
return null;//验证失败返回null值
}
}