基本概念
身份验证
即在应用中谁能证明他就是他本人。一般提供如他们的身份ID 一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。在 shiro 中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份
principals
身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。
证明/凭证
即只有主体知道的安全值,如密码/数字证书等。
最常见的principals和credentials组合就是用户名/密码了。
认证流程
用户登陆认证
导入jar包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
配置shiro环境文件shiro.ini
[users]
root=123
public static void main(String[] args) {
//创建SecurityManager工厂,读取配置文件
//注意导包
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//通过SecurityManager工厂获取SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//将SecurityManager对象设置到环境中
SecurityUtils.setSecurityManager(securityManager);
//通过SecurityUtils获取主体Subject
Subject subject = SecurityUtils.getSubject();
//用户登陆的用户名和密码,而ini文件中的用户名和密码相当数据库中的user
UsernamePasswordToken token = new UsernamePasswordToken("root", "123");
try {
//进行用户身份验证,如果验证失败则抛出异常
subject.login(token);
//判断用户是否通过验证
if (subject.isAuthenticated()) {
System.out.println("登陆成功");
}
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("用户登陆失败");
}
}
自定义Realm
Shiro默认使用自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。
最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm。
自定义Realm实现
public class UserRealm extends AuthorizingRealm {
public String getName(){
return "userRealm";
}
/**
* @Description:获取权限信息
* @param principals
* @return
*/
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
return null;
}
/**
* @Description:完成身份认证
* @param token
* @return
* @throws AuthenticationException
*/
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
//获取用户输入的用户名
String username = (String) token.getPrincipal();
System.out.println("第一个Realm:");
System.out.println("username===="+username);
//根据用户名查询数据库获取密码
String password = "123";
//将从数据库中获取的信息封装到
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,password,getName());
return info;
}
}
要想使用自定义的realm需要先在shiro.ini中配置Realm,类似于spring的依赖注入
[main]
#自定义 realm
userRealm=com.QEcode.realm.UserRealm
#将realm设置到securityManager
securityManager.realms=$userRealm
Authenticator
Authenticator 的职责是验证用户帐号,是 Shiro API 中身份验证核心的入口点.
如果验证成功,将返回 AuthenticationInfo 验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的 AuthenticationException 实现。
SecurityManager 接口继承了 Authenticator,另外还有一个 ModularRealmAuthenticator 实现,其委托给多个 Realm 进行验证,验证规则通过 AuthenticationStrategy 接口指定,默认提供的实现:
FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一个 Realm 验证成功即可,和 FirstSuccessfulStrategy不同,返回所有 Realm 身份验证成功的认证信息;
AllSuccessfulStrategy:所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的认证信息,如果有一个失败就失败了。
ModularRealmAuthenticator 默认使AtLeastOneSuccessfulStrategy 策略。
在ini 配置文件中指定
[main]
userRealm = com.QEcode.realm.UserRealm
userRealm2 = com.QEcode.realm.UserRealm2
# 配置验证器
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
# 指定验证规则为AllSuccessfulStrategy 所有 Realm 验证成功才算成功,
allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
# 指定验证规则为AtLeastOneSuccessfulStrategy 只要有一个 Realm 验证成功返回所有 Realm 身份验证成功的认证信息
atLeastOneSuccessfulStrategy = org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
# 指定验证规则为FirstSuccessfulStrategy 只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息
firstSuccessfulStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
#指定 securityManager 的 authenticator 实现
authenticator.authenticationStrategy=$firstSuccessfulStrategy
securityManager.authenticator=$authenticator
securityManager.realms=$userRealm , $userRealm2
public class UserRealm2 extends AuthorizingRealm {
public String getName(){
return "userRealm2";
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// TODO 自动生成的方法存根
return null;
}
/**
* @Description:身份认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// 获取用户输入的用户名
String username = (String) token.getPrincipal();
System.out.println("第二个Realm:");
System.out.println("username====" + username);
// 根据用户名查询数据库获取密码
String password = "123";
// 将从数据库中获取的信息封装到
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,
password, getName());
return null;
}
}