30、shiro框架入门2,关于Realm
1、Jdbc的Realm链接,并且获取权限
首先创建shiro-jdbc.ini的配置文件,主要配置链接数据库的信息
配置文件中的内容如下所示
1、变量名=全限定类名会自动创建一个类实例
2、变量名.属性=值 自动调用相应的setter方法进行赋值
3、$变量名 引用之前的一个对象实例
4、测试代码请参照com.github.zhangkaitao.shiro.chapter2.LoginLogoutTest的testJDBCRealm方法,和之前的没什么区别。
到数据库shiro下建三张表:users(用户名/密码)、user_roles(用户/角色)、roles_permissions(角色/权限),具体请参照shiro-example-chapter2/sql/shiro.sql;并添加一个用户记录,用户名/密码为zhang/123;
USE shiro; CREATE TABLE users ( id BIGINT AUTO_INCREMENT, username VARCHAR(100), PASSWORD VARCHAR(100), password_salt VARCHAR(100), CONSTRAINT pk_users PRIMARY KEY(id) ) CHARSET=utf8 ENGINE=INNODB; CREATE UNIQUE INDEX idx_users_username ON users(username); CREATE TABLE user_roles( id BIGINT AUTO_INCREMENT, username VARCHAR(100), role_name VARCHAR(100), CONSTRAINT pk_user_roles PRIMARY KEY(id) ) CHARSET=utf8 ENGINE=INNODB; CREATE UNIQUE INDEX idx_user_roles ON user_roles(username, role_name); CREATE TABLE roles_permissions( id BIGINT AUTO_INCREMENT, role_name VARCHAR(100), permission VARCHAR(100), CONSTRAINT pk_roles_permissions PRIMARY KEY(id) ) CHARSET=utf8 ENGINE=INNODB; CREATE UNIQUE INDEX idx_roles_permissions ON roles_permissions(role_name, permission); INSERT INTO users(username,PASSWORD)VALUES('zhang','123');
然后就是单元测试的过程,java通过读取realm-jdbc.ini文件获取权限,角色,用户名称等
@Test public void testJDBCRealm() { //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-jdbc.ini"); //2、得到SecurityManager实例 并绑定给SecurityUtils org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); try { //4、登录,即身份验证 subject.login(token); } catch (AuthenticationException e) { } Assert.assertEquals(true, subject.isAuthenticated()); //6、退出 subject.logout(); }
二、
Authenticator及AuthenticationStrategy
Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点:
public AuthenticationInfo authenticate(AuthenticationToken authenticationToken) throws AuthenticationException;
如果验证成功,将返回AuthenticationInfo验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的AuthenticationException实现。
SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:
FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。
[main] #指定securityManager的authenticator实现 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator securityManager.authenticator=$authenticator #指定securityManager.authenticator的authenticationStrategy allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy myRealm1=realm.MyRealm1 myRealm2=realm.MyRealm2 securityManager.realms=$myRealm1,$myRealm2
package realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.Realm; public class MyRealm2 implements Realm{ 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("zhang@163.com", "123", getName()); } public String getName() { return "myrealm2"; } public boolean supports(AuthenticationToken token) { //仅支持UsernamePasswordToken类型的Token return token instanceof UsernamePasswordToken; } }
package realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.Realm; public class MyRealm1 implements Realm{ 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()); } public String getName() { return "myrealm1"; } public boolean supports(AuthenticationToken token) { //仅支持UsernamePasswordToken类型的Token return token instanceof UsernamePasswordToken; } }
@Test public void testMoreAuthention() { login("classpath:shiro-authenticator-all-success.ini"); Subject subject = SecurityUtils.getSubject(); //得到一个身份集合,其包含了Realm验证成功的身份信息 PrincipalCollection collection=subject.getPrincipals(); Assert.assertEquals(2, collection.asList().size()); }
最后测试好像不太好使
login方法
public void login(String config){ System.out.println(config); Factory<org.apache.shiro.mgt.SecurityManager> factory= new IniSecurityManagerFactory(config); org.apache.shiro.mgt.SecurityManager manager = (org.apache.shiro.mgt.SecurityManager) factory.getInstance(); SecurityUtils.setSecurityManager(manager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); subject.login(token); }