认识Realm
在Shiro里面考虑到以后可能面对于不同的用户数据的来源,所以为了统一这些来源的处理,准备了一个Realm接口,首先来观察org.apache.shiro.realm.Realm接口定义:
public interface Realm {
/**
* Returns the (application-unique) name assigned to this <code>Realm</code>. All realms configured for a single
* application must have a unique name.
*
* @return the (application-unique) name assigned to this <code>Realm</code>.
*/
String getName();
/**
* Returns <tt>true</tt> if this realm wishes to authenticate the Subject represented by the given
* {@link org.apache.shiro.authc.AuthenticationToken AuthenticationToken} instance, <tt>false</tt> otherwise.
*
* <p>If this method returns <tt>false</tt>, it will not be called to authenticate the Subject represented by
* the token - more specifically, a <tt>false</tt> return value means this Realm instance's
* {@link #getAuthenticationInfo} method will not be invoked for that token.
*
* @param token the AuthenticationToken submitted for the authentication attempt
* @return <tt>true</tt> if this realm can/will authenticate Subjects represented by specified token,
* <tt>false</tt> otherwise.
*/
boolean supports(AuthenticationToken token);
/**
* Returns an account's authentication-specific information for the specified <tt>token</tt>,
* or <tt>null</tt> if no account could be found based on the <tt>token</tt>.
*
* <p>This method effectively represents a login attempt for the corresponding user with the underlying EIS datasource.
* Most implementations merely just need to lookup and return the account data only (as the method name implies)
* and let Shiro do the rest, but implementations may of course perform eis specific login operations if so
* desired.
*
* @param token the application-specific representation of an account principal and credentials.
* @return the authentication information for the account associated with the specified <tt>token</tt>,
* or <tt>null</tt> if no account could be found.
* @throws org.apache.shiro.authc.AuthenticationException
* if there is an error obtaining or constructing an AuthenticationInfo object based on the
* specified <tt>token</tt> or implementation-specifc login behavior fails.
*/
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
}
固定信息Realm认证
如果要想使用Realm操作,那么必须要保证有一个具体的认证类实现了Realm接口。
1、 建立一个MyRealm子类,该类实现Realm接口;
· 认证信息:org.apache.shiro.authc.AuthenticationInfo,接口有两个方法:
|- 取得所有的身份信息:public PrincipalCollection getPrincipals();
|- 取得认证信息:public Object getCredentials()。
· 子类:org.apache.shiro.authc.SimpleAuthenticationInfo;
|- 构造方法:public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName)。
· 所有用户的信息都保存在token里面:org.apache.shiro.authc.AuthenticationToken,此接口定义有如下两个方法: |- 身份数据:public Object getPrincipal();
|- 认证数据:public Object getCredentials()。
|- 此时返回的数据为char[]数组,不能直接转换为String;
实现自定义Realm
public class MyRealm implements Realm {
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal() ;
// 取得用户名
// 在Shiro里面是利用字符数组实现了密码的传递,所以不能将其直接变为String
String password = new String((char[]) token.getCredentials()) ;
// 取得密码
// 此时直接使用一个固定的用户名和密码进行验证处理操作
if (!"admin".equals(username)) {
// 判断用户名是否存在
throw new UnknownAccountException("用户名不存在!") ;
}
if (!"hello".equals(password)) {
throw new IncorrectCredentialsException("密码输入错误!") ;
}
return new SimpleAuthenticationInfo(username,password,this.getName()) ;
} @Override public String getName() {
return "MyRealm";
// 名字随便给一个,只要能唯一标记即可
}
@Override public boolean supports(AuthenticationToken token) {
// 本次将在之前程序的基础之上继续使用UsernamePasswordToken完成信息的传递
return token instanceof UsernamePasswordToken ;
}
}
}
如果现在希望realm配置生效,则需要在配置文件里面进行相关定义。
修改shiro.ini文件
myRealm=cn.realm.MyRealm
这个时候一定要注意,如果有多个Realm,则在“securityManager.realms”后面可以设置多个名称,中间使用“,”分割。
使用该Realm进行数据的认证处理:
public class TestLoginDemo {
public static void main(String[] args) {
// 取得Factory接口对象,主要的目的是通过配置文件加载文件之中的信息,这些信息暂时不能够成为认证信息
Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
// 取得里面所保存的所有的认证数据信息 org.apache.shiro.mgt.SecurityManager
securityManager = factory.getInstance(); //
// 利用一个专门的认证操作的处理类,实现认证处理的具体的实现
SecurityUtils.setSecurityManager(securityManager); //
// 获取进行用户名和密码认证的接口对象
Subject subject = SecurityUtils.getSubject();
// 定义了一个Token,里面保存要登录的用户名和密码信息
UsernamePasswordToken token = new UsernamePasswordToken("admin", "hello");
// 实现用户登录处理
subject.login(token);
System.out.println(subject.getPrincipal());
// 取得用户名
}
}
基于数据库的验证处理
需要建立一张用户表:member;
表中需要拥有以下字段:
mid,password,name,locked(锁定标记)
处理操作所有的核心配置都不是通过程序完成的,都是通过配置文件完成的,可以直接使用MySQL 提供好的
数据库连接池配置。
修改shiro.ini 的文件
[main]
dataSource=com.mysql.jdbc.jdbc2.optional.MysqlDataSource
#定义数据库的连接主机名称 dataSource.serverName=127.0.0.1
#定义要使用的数据库的名字 dataSource.databaseName=shirodb
#定义数据库的连接账户 dataSource.user=root
#定义数据库的连接的密码 dataSource.password=mysqladmin
#定义本次要基于JDBC实现的Realm的认证的配置类 jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
#配置本次的JDBC连接所使用的数据源,$表示引用配置
jdbcRealm.dataSource=$dataSource
#定义所需要的查询语句 jdbcRealm.authenticationQuery=SELECT password FROM member WHERE mid=?
# 配置安全管理器所使用的
Realm securityManager.realms=$jdbcRealm
此时继续使用之前的程序进行执行,这个时候将利用JDBC实现用户的登录检测操作。