自定义 Realm
上边的程序使用的是 Shiro 自带的 IniRealm,IniRealm 从 INI 配置文件中读取用户的信息, 大部分情况下需要从系统的数据库中读取用户信息, 所以需要自定义 realm.
realm 的接口
image.PNG
最基础的是 Realm 接口, CachingRealm 负责缓存处理, AuthenticationRealm 负责认证, AuthorizingRealm 负责授权, 通常自定义的 realm 继承 AuthorizingRealm.
在认证, 授权内部实现机制中都有提到, 最终处理都将交给 Real 进行处理. 因为在 Shiro 中, 最终是通过 Realm 来获取应用程序中的用户, 角色及权限信息的. 通常情况下, 在 Realm 中会直接从我们的数据源中获取 Shiro 需要的验证信息. 可以说, Realm 是专用于安全框架的 DAO.
认证实现
Shiro 的认证过程最终会交由 Realm 执行, 这时会调用 Realm 的 getAuthenticationInfo(token)方法. 该方法主要执行以下操作: 1, 检查提交的进行认证的令牌信息 2, 根据令牌信息从数据源 (通常为数据库) 中获取用户信息 3, 对用户信息进行匹配验证. 4, 验证通过将返回一个封装了用户信息的 AuthenticationInfo 实例. 5, 验证失败则抛出 AuthenticationException 异常信息.
配置 shiro-realm.INI
- [main]
- #\u81ea\u5b9a\u4e49 realm
- customRealm=cn.itcast.shiro.realm.CustomRealm
- #\u5c06realm\u8bbe\u7f6e\u5230securityManager\uff0c\u76f8\u5f53 \u4e8espring\u4e2d\u6ce8\u5165
- securityManager.realms=$customRealm
CustomRealm.java
image.PNG
CustomRealm.java
- package cn.itcast.shiro.realm;
- import java.util.ArrayList;
- import java.util.List;
- 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.authz.AuthorizationInfo;
- import org.apache.shiro.authz.SimpleAuthorizationInfo;
- import org.apache.shiro.realm.AuthorizingRealm;
- import org.apache.shiro.subject.PrincipalCollection;
- /**
- *
- * <p>
- * Title: CustomRealm
- * </p>
- * <p>
- * Description: 自定义 realm
- * </p>
- * <p>
- * Company: www.itcast.com
- * </p>
- *
- * @author 传智. 燕青
- * @date 2015-3-23 下午 4:54:47
- * @version 1.0
- */
- public class CustomRealm extends AuthorizingRealm {
- // 设置 realm 的名称
- @Override
- public void setName(String name) {
- super.setName("customRealm");
- }
- // 用于认证
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(
- AuthenticationToken token) throws AuthenticationException {
- // token 是用户输入的
- // 第一步从 token 中取出身份信息
- String userCode = (String) token.getPrincipal();
- // 第二步: 根据用户输入的 userCode 从数据库查询
- // ....
- // 如果查询不到返回 null
- // 数据库中用户账号是 zhangsansan
- /*if(!userCode.equals("zhangsansan")){//
- return null;
- }*/
- // 模拟从数据库查询到密码
- String password = "111111";
- // 如果查询到返回认证信息 AuthenticationInfo
- SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
- userCode, password, this.getName());
- return simpleAuthenticationInfo;
- }
- // 用于授权
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(
- PrincipalCollection principals) {
- // 从 principals 获取主身份信息
- // 将 getPrimaryPrincipal 方法返回值转为真实身份类型(在上边的 doGetAuthenticationInfo 认证通过填充到 SimpleAuthenticationInfo 中身份类型),
- String userCode = (String) principals.getPrimaryPrincipal();
- // 根据身份信息获取权限信息
- // 连接数据库...
- // 模拟从数据库获取到数据
- List<String> permissions = new ArrayList<String>();
- permissions.add("user:create");// 用户的创建
- permissions.add("items:add");// 商品添加权限
- //....
- // 查到权限数据, 返回授权信息(要包括 上边的 permissions)
- SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
- // 将上边查询到授权信息填充到 simpleAuthorizationInfo 对象中
- simpleAuthorizationInfo.addStringPermissions(permissions);
- return simpleAuthorizationInfo;
- }
- }
测试
AuthenticationTest.java
- // 自定义 realm
- @Test
- public void testCustomRealm() {
- // 创建 securityManager 工厂, 通过 INI 配置文件创建 securityManager 工厂
- Factory<SecurityManager> factory = new IniSecurityManagerFactory(
- "classpath:shiro-realm.ini");
- // 创建 SecurityManager
- SecurityManager securityManager = factory.getInstance();
- // 将 securityManager 设置当前的运行环境中
- SecurityUtils.setSecurityManager(securityManager);
- // 从 SecurityUtils 里边创建一个 subject
- Subject subject = SecurityUtils.getSubject();
- // 在认证提交前准备 token(令牌)
- // 这里的账号和密码 将来是由用户输入进去
- UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
- "111111");
- try {
- // 执行认证提交
- subject.login(token);
- } catch (AuthenticationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- // 是否认证通过
- boolean isAuthenticated = subject.isAuthenticated();
- System.out.println("是否认证通过:" + isAuthenticated);
- }
- // 自定义 realm 实现散列值匹配
- @Test
- public void testCustomRealmMd5() {
- // 创建 securityManager 工厂, 通过 INI 配置文件创建 securityManager 工厂
- Factory<SecurityManager> factory = new IniSecurityManagerFactory(
- "classpath:shiro-realm-md5.ini");
- // 创建 SecurityManager
- SecurityManager securityManager = factory.getInstance();
- // 将 securityManager 设置当前的运行环境中
- SecurityUtils.setSecurityManager(securityManager);
- // 从 SecurityUtils 里边创建一个 subject
- Subject subject = SecurityUtils.getSubject();
- // 在认证提交前准备 token(令牌)
- // 这里的账号和密码 将来是由用户输入进去
- UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
- "222222");
- try {
- // 执行认证提交
- subject.login(token);
- } catch (AuthenticationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- // 是否认证通过
- boolean isAuthenticated = subject.isAuthenticated();
- System.out.println("是否认证通过:" + isAuthenticated);
- }
来源: http://www.jianshu.com/p/5d43d05ca46b