今天来学习一下shrio自定义realm,首先,在这里定义一个我们的realm,没有做任何的操作,如下。
public class MyRealm extends AuthorizingRealm{
@Override
public String getName() {
return "MyRealm";
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println(authenticationToken);
return null;
}
}
接下来要做的是,如何从登陆页跳转到该代码,好了,首先下面是一个登陆代码。
@Test
public void testByRealm(){
//创建工厂对象
Factory<SecurityManager> factory= new IniSecurityManagerFactory("classpath:shrio-realm.ini");
SecurityManager securityManager=factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//创建登陆主体subject
Subject subject=SecurityUtils.getSubject();
//绑定主体
UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123456");
//主体登陆
try {
subject.login(token);
}catch (AuthenticationException e){
System.out.println(e.fillInStackTrace());
}
System.out.println("登陆是否成功了:"+String.valueOf(subject.isAuthenticated()));
//退出
subject.logout();
}
我们在subject.login登陆中,打一下debug.进入到了DelegatingSubject。
public void login(AuthenticationToken token) throws AuthenticationException {
this.clearRunAsIdentitiesInternal();
Subject subject = this.securityManager.login(this, token);
String host = null;
PrincipalCollection principals;
if (subject instanceof DelegatingSubject) {
DelegatingSubject delegating = (DelegatingSubject)subject;
principals = delegating.principals;
host = delegating.host;
} else {
principals = subject.getPrincipals();
}
if (principals != null && !principals.isEmpty()) {
this.principals = principals;
this.authenticated = true;
if (token instanceof HostAuthenticationToken) {
host = ((HostAuthenticationToken)token).getHost();
}
if (host != null) {
this.host = host;
}
Session session = subject.getSession(false);
if (session != null) {
this.session = this.decorate(session);
} else {
this.session = null;
}
} else {
String msg = "Principals returned from securityManager.login( token ) returned a null or empty value. This value must be non null and populated with one or more elements.";
throw new IllegalStateException(msg);
}
}
在代理的object中,我们进入到Subject subject = this.securityManager.login(this, token);在DefaultSecurityManager的login中,将会执行验证过程。this.authenticate(token)。
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info;
try {
info = this.authenticate(token);
} catch (AuthenticationException var7) {
AuthenticationException ae = var7;
try {
this.onFailedLogin(token, ae, subject);
} catch (Exception var6) {
if (log.isInfoEnabled()) {
log.info("onFailedLogin method threw an exception. Logging and propagating original AuthenticationException.", var6);
}
}
throw var7;
}
Subject loggedIn = this.createSubject(token, info, subject);
this.onSuccessfulLogin(token, info, loggedIn);
return loggedIn;
}
进入到验证。在AuthenticatingSecurityManager中authenticate,我们来验证。
public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
return this.authenticator.authenticate(token);
}
在AbstractAuthenticator中,我们进入到info = this.doAuthenticate(token)
public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
if (token == null) {
throw new IllegalArgumentException("Method argumet (authentication token) cannot be null.");
} else {
log.trace("Authentication attempt received for token [{}]", token);
AuthenticationInfo info;
try {
info = this.doAuthenticate(token);
if (info == null) {
String msg = "No account information found for authentication token [" + token + "] by this " + "Authenticator instance. Please check that it is configured correctly.";
throw new AuthenticationException(msg);
}
} catch (Throwable var8) {
AuthenticationException ae = null;
if (var8 instanceof AuthenticationException) {
ae = (AuthenticationException)var8;
}
if (ae == null) {
String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " + "error? (Typical or expected login exceptions should extend from AuthenticationException).";
ae = new AuthenticationException(msg, var8);
}
try {
this.notifyFailure(token, ae);
} catch (Throwable var7) {
if (log.isWarnEnabled()) {
String msg = "Unable to send notification for failed authentication attempt - listener error?. Please check your AuthenticationListener implementation(s). Logging sending exception and propagating original AuthenticationException instead...";
log.warn(msg, var7);
}
}
throw ae;
}
log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info);
this.notifySuccess(token, info);
return info;
}
}
接下来,在ModularRealmAuthenticator中,我们获取realm。
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
this.assertRealmsConfigured();
Collection<Realm> realms = this.getRealms();
return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);
}
如下所示,我们来看到我们定义的realm。
同样,在该类中,我们看到了,我们就要进入到我们自定义的realm了。
protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
if (!realm.supports(token)) {
String msg = "Realm [" + realm + "] does not support authentication token [" + token + "]. Please ensure that the appropriate Realm implementation is " + "configured correctly or that the realm accepts AuthenticationTokens of this type.";
throw new UnsupportedTokenException(msg);
} else {
AuthenticationInfo info = realm.getAuthenticationInfo(token);
if (info == null) {
String msg = "Realm [" + realm + "] was unable to find account data for the " + "submitted AuthenticationToken [" + token + "].";
throw new UnknownAccountException(msg);
} else {
return info;
}
}
}
我们来看一下AuthenticationRealm中的getAuthenticationInfo函数的info = this.doGetAuthenticationInfo(token);进入到我们的定义realme,如下所示。是不是有一种凯旋而归的感觉。
好了,现在我们来重写一下我们的realm。在认证函数中。做相应的处理。
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println(token);
//获取token的用户名
String username = (String) token.getPrincipal();
if (!"zhangsan".equals(username)){
return null;
}
String password="123456";
//参数一:当前登陆用户名,参数二:数据库的密码,参数三:当前realm的名字
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
return info;
}
我们来运行一下。当用户名和密码成功设置的时候,运行成功。
下面来改一下用户名。则会报如下的错误。
而当我们修改一下密码。则会报如下的错误。