openfire源码解读--用户登录
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了openfire源码解读--用户登录相关的知识,希望对你有一定的参考价值。
根据xmpp协议
客户端发送:
<auth xmlns=‘urn:ietf:params:xml:ns:xmpp-sasl‘ mechanism=‘PLAIN‘>XXXXXXXXXXXXXXXXXXXXX=</auth>
其中,xmlns是命名空间,mechanism是用户名密码的加密方式,auth 标签的text内容为用户名密码通过PLAIN方式加密的字符串。
服务端接收:
通过ConnectionHandler类的messageReceived方法接收,process中处理
else if ("auth".equals(tag)) { // User is trying to authenticate using SASL startedSASL = true; // Process authentication stanza saslStatus = SASLAuthentication.handle(session, doc); }
判断xml标签为auth时进行登录验证。
下面来看SASLAuthentication的处理
首先判断加密方式,然后解密,通过下面这个方法来验证登录。
final byte[] challenge = saslServer.evaluateResponse( decoded ); // Either a challenge or success data.
根据加密方式不同,验证处理方法不同。PLAIN加密的,那就看SaslServerPlainImpl中是怎么实现的。
NameCallback ncb = new NameCallback("PLAIN authentication ID: ",principal); VerifyPasswordCallback vpcb = new VerifyPasswordCallback(password.toCharArray()); cbh.handle(new Callback[]{ncb,vpcb}); if (vpcb.getVerified()) { vpcb.clearPassword(); AuthorizeCallback acb = new AuthorizeCallback(principal,username); cbh.handle(new Callback[]{acb}); if(acb.isAuthorized()) { username = acb.getAuthorizedID(); completed = true; } else { completed = true; username = null; throw new SaslException("PLAIN: user not authorized: "+principal); } } else { throw new SaslException("PLAIN: user not authorized: "+principal); }
可以看到openfire是通过callback来验证的,而且还进行了2层验证。第一次是验证用户名密码,第二次是加载用户信息
(自己有需要修改源码时,这里就可以优化了,第一步登录验证时就可以获取用户信息了,没必要重新查询一次)。
callback是通过XMPPCallbackHandler实现的。
for (Callback callback : callbacks) { if (callback instanceof RealmCallback) { ((RealmCallback) callback).setText( XMPPServer.getInstance().getServerInfo().getXMPPDomain() ); } else if (callback instanceof NameCallback) { name = ((NameCallback) callback).getName(); if (name == null) { name = ((NameCallback) callback).getDefaultName(); } //Log.debug("XMPPCallbackHandler: NameCallback: " + name); } else if (callback instanceof PasswordCallback) { try { // Get the password from the UserProvider. Some UserProviders may not support // this operation ((PasswordCallback) callback) .setPassword(AuthFactory.getPassword(name).toCharArray()); //Log.debug("XMPPCallbackHandler: PasswordCallback"); } catch (UserNotFoundException | UnsupportedOperationException e) { throw new IOException(e.toString()); } } else if (callback instanceof VerifyPasswordCallback) { //Log.debug("XMPPCallbackHandler: VerifyPasswordCallback"); VerifyPasswordCallback vpcb = (VerifyPasswordCallback) callback; try { AuthToken at = AuthFactory.authenticate(name, new String(vpcb.getPassword())); vpcb.setVerified((at != null)); } catch (Exception e) { vpcb.setVerified(false); } } else if (callback instanceof AuthorizeCallback) { //Log.debug("XMPPCallbackHandler: AuthorizeCallback"); AuthorizeCallback authCallback = ((AuthorizeCallback) callback); // Principal that authenticated String principal = authCallback.getAuthenticationID(); // Username requested (not full JID) String username = authCallback.getAuthorizationID(); // Remove any REALM from the username. This is optional in the spec and it may cause // a lot of users to fail to log in if their clients is sending an incorrect value if (username != null && username.contains("@")) { username = username.substring(0, username.lastIndexOf("@")); } if (principal.equals(username)) { //client perhaps made no request, get default username username = AuthorizationManager.map(principal); if (Log.isDebugEnabled()) { //Log.debug("XMPPCallbackHandler: no username requested, using " + username); } } if (AuthorizationManager.authorize(username, principal)) { if (Log.isDebugEnabled()) { //Log.debug("XMPPCallbackHandler: " + principal + " authorized to " + username); } authCallback.setAuthorized(true); authCallback.setAuthorizedID(username); } else { if (Log.isDebugEnabled()) { //Log.debug("XMPPCallbackHandler: " + principal + " not authorized to " + username); } authCallback.setAuthorized(false); } }
第一次验证用户名密码是通过 AuthToken at = AuthFactory.authenticate(name, new String(vpcb.getPassword()));验证的
根据数据库配置provider.auth.className的类实现登录验证。
第二次验证AuthorizationManager.authorize(username, principal)会加载用户信息。
2次验证通过就会返回客户端 <success xmlns=‘urn:ietf:params:xml:ns:xmpp-sasl‘/> 表示登录成功。
以上是关于openfire源码解读--用户登录的主要内容,如果未能解决你的问题,请参考以下文章