shiro Realm详解
Realm提供待验证数据的比对值,即安全数据源,可以理解为数据的源头,可以是数据库,文件等。Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作。
接口
public class MyRealm1 implements Realm { String getName(); //返回一个唯一的Realm名字 boolean supports(AuthenticationToken token); //判断此Realm是否支持此Token AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException; //根据Token获取认证信息 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) //授权 }
身份验证(getAuthenticationInfo 方法)验证账户和密码,并返回相关信息
权限获取(getAuthorizationInfo 方法) 获取指定身份的权限,并返回相关信息
令牌支持(supports方法)判断该令牌(Token)是否被支持,令牌有很多种类型,例如:HostAuthenticationToken(主机验证令牌),UsernamePasswordToken(账户密码验证令牌)
doGetAuthorizationInfo获取身份验证相关信息:PrincipalCollection 是一个身份集合。可以调用getPrimaryPrincipal等方法得到之前传入的用户名,再根据用户名调用 UserService接口获取角色及权限信息
类图
一般自定以realm都会继承AuthorizingRealm抽象类,并实现getAuthenticationInfo和getAuthorizationInfo方法,来完成登录和权限的验证。当然也可以直接继承realm。
分类
org.apache.shiro.realm.text.IniRealm
shiro.ini中[users]部分指定用户名/密码及其角色;[roles]部分指定角色即权限信息;
org.apache.shiro.realm.text.PropertiesRealm
shiro.ini中user.username=password,role1,role2指定用户名/密码及其角色;role.role1=permission1,permission2指定角色及权限信息;
org.apache.shiro.realm.jdbc.JdbcRealm
通过sql查询相应的信息
自定义单Realm
//shiro.ini配置 [main] #声明一个realm myRealm1=org.shiro.realm.MyRealm1 #指定securityManager的realms实现 securityManager.realms=$myRealm1 //relam.java public class MyRealm1 implements Realm { @Override public String getName() { return "www.51gjie.com";//返回一个realm名 } @Override public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken;//仅支持UsernamePasswordToken类型的token } @Override public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal();//得到用户名 String password = new String((char[])token.getCredentials());//得到用户密码 if(!"zhang".equals(username)){ throw new UnknownAccountException();//身份验证失败 } if(!"123".equals(password)){ throw new IncorrectCredentialsException();//密码验证失败 } //如果身份认证验证成功,返回一个AuthenticationInfo实现; return new SimpleAuthenticationInfo(username,password,getName()); } } //test.java @Test public void testShirorealm(){ //1.得到securityManager并实例化 IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); //2.绑定给SecurityUtils SecurityUtils.setSecurityManager(securityManager); //3.得到subject和进行用户身份验证的token Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhang","123"); try{ //登陆 subject.login(token); }catch (AuthenticationException e){ } //退出登陆 subject.logout(); }
多Realm
如果有多个Realm,那么securityManager会按照shiro.ini中realms指定的顺序进行身份认证。
//shiro.ini配置 [main] #声明一个realm myRealm1=org.wct.shiro.realm.MyRealm1 myRealm2=org.wct.shiro.realm.MyRealm2 #指定securityManager的realms实现 securityManager.realms=$myRealm1,$myRealm2 //MyRealm2.java public class MyRealm2 implements Realm { @Override public String getName() { return "www.51gjie.com"; } @Override public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; } @Override public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); String password = new String((char[]) token.getCredentials()); if(!"wang".equals(username)){ throw new UnknownAccountException(); } if (!"123".equals(password)){ throw new IncorrectCredentialsException(); } return new SimpleAuthenticationInfo(username,password,getName()); } }
myrealm1是单realm例子,测试方法也一致。此处我们使用显示指定顺序的方式指定了 Realm 的顺序,SecurityManager会先执行myRealm1,然后执行myRealm2。
总结
1. Realm 充当了 Shiro 与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息。从这个意义上讲,Realm 实质上是一个安全相关的 DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给 Shiro 。当配置 Shiro时,你必须至少指定一个 Realm ,用于认证和(或)授权。配置多个 Realm 是可以的,但是至少需要一个。
2. Shiro 内置了可以连接大量安全数据源(又名目录)的 Realm,如 LDAP、关系数据库(JDBC)、类似 INI 的文本配置资源以及属性文件等。
版权声明:本文为JAVASCHOOL原创文章,未经本站允许不得转载。