身份认证流程
流程图.png流程如下:
- 通过
Subject
对象的login(token)
方法登录,其会委托给Security Manager
; -
SecurityManager
负责正的身份验证逻辑,它会委托给Authenticator
进行身份验证; -
Autenticator
才是真正的身份验证者,此处可自己实现。 -
Autenticator
可能会委托给AuthenticationStrategy
进行多Realm
身份验证 -
Autenticator
会把登录时传入的token
对象,传给Realm
,验证成功后会返回AuthenticationInfo
对象,此对象中包含用户的身份及凭证,如果认证失败会抛出AuthenticationException
异常。此处可以配置多个 Realm,将按照相应的顺序及策略进行验证。
Authenticator
Authenticator
有多种已实现的验证规则,可以通过 AuthenticationStrategy
接口指定,已经实现的验证规则有:
认证策略:
-
FirstSuccessfulStrategy
:通过有一个Realm
验证即通过验证,会返回第一个通过的Realm
认证信息 -
AtLeastOneSuccessfulStrategy
:同样一个通过即可,但是这个会返回所有Realm
身份验证成功的认证信息 -
AllSuccessfulStrategy
:这个比较严厉,要通过所有的Realm
验证才算成功,且返回所有的Realm
的认证信息
默认使用的是 AtLeastOneSuccessfulStrategy
验证策略;
代码实例
创建三个自定义的 Realm
:
myRealm1: 用户名 / 密码为 admin/ad123 时成功,且返回身份 / 凭据为 admin/ad123;
myRealm2: 用户名 / 密码为 admin2/123 时成功,且返回身份 / 凭据为 admin2/ad123;
myRealm3: 用户名 / 密码为 admin/ad123 时成功,且返回身份 / 凭据为admin@163.com/123
myRealm1:
package shiro02;
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 {
@Override
public String getName() {
return "MyRealm1";
}
@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 (!"admin".equals(username)) {
throw new UnknownAccountException();
}
// 如果密码错误
if (!"ad123".equals(password)) {
throw new IncorrectCredentialsException();
}
// 验证通过
return new SimpleAuthenticationInfo(username, password, getName());
}
}
myRealm2 改变上面用户名与密码的字符串
myRealm3 将 return 语句改成 return new SimpleAuthenticationInfo(username + "@163.com", password, getName());
配置文件
shiro-authenticator-all-success.ini
#指定SecurityManager的authenticator实现
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
securityManager.authenticator=$authenticator
# 声明验证策略
allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
# 指定策略
securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
# 声明 realm
myRealm1=shiro02.MyRealm1
myRealm2=shiro02.MyRealm2
myRealm3=shiro02.MyRealm3
# 指定多个 realm
securityManager.realms=$myRealm1,$myRealm3
测试
package shiro02;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;
public class AuthenticatorTest {
private void login(String configFile) {
// 获取SecurityManager工厂
Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory(
configFile);
// 获通过工厂获取SecurityManager实例
SecurityManager securityManager = factory.getInstance();
// 将实例绑定给SecurityUtils
SecurityUtils.setSecurityManager(securityManager);
// 获取Subject
Subject subject = SecurityUtils.getSubject();
// 创建Token
UsernamePasswordToken token = new UsernamePasswordToken("admin", "ad123");
// 登录(验证用户)
try {
subject.login(token);
} catch (AuthenticationException e) {
// 验证失败
e.printStackTrace();
}
if (subject.isAuthenticated()) {
System.out.println("登录成功!!!");
}
}
@Test
public void testAllSuccessfulStrategyWithSuccess() {
this.login("classpath:shiro-authenticator-all-success.ini");
Subject subject = SecurityUtils.getSubject();
// 得到身份集合,包含Realm验证成功的身份信息
PrincipalCollection principalCollection = subject.getPrincipals();
System.out.println(principalCollection.asList());
}
}
网友评论