1. 登录集成
通过登录接口可以定制自己的登录认证,或者对登录进行拦截,在登录前、登录成功、登录失败的各个环节记录日志。
1.1. 自定义登录认证LoginAuthentication
登录验证器
典型应用场景如下:
- AD/LDAP统一认证
- 两步认证,使用手机短信、手机令牌或其他硬件进行双因素认证
- CA认证实现
/**
* 认证,策略是:
*
* <ol>
* <li>系统框架把登录界面发过来的<code>HttpServletRequest</code>完整的传递给认证实现类</li>
* <li>认证实现类完成自己的逻辑</li>
* <li>返回值约定
* <ol type="i">
* <li>当验证通过,需要给框架返回[用户名, 密码],框架将直接跳转到首页</li>
* <li>当不验证通过,但要终止本次登录请求,直接throw new LoginAuthenticationException(),用户将跳转到登录页</li>
* <li>当不验证通过,返回null,框架将调用下一个认证类认证</li>
* </ol>
* </li>
* </ol>
*
* @return 认证通过: 返回[用户名, 密码]; 验证不通过返回null,框架将调用下一个认证类认证
* @throws LoginAuthenticationException 用户将跳转到登录页
*/
String[] authenticate(HttpServletRequest request, HttpServletResponse response)
throws LoginAuthenticationException;
系统缺省提供几个验证器,按顺序如下
验证器 | 说明 |
---|---|
com.seeyon.ctp.portal.sso.login.SSOTicketLoginAuthentication | 单点登录认证 |
com.seeyon.v3x.plugin.ca.CALoginAuthentication | 使用CA认证 |
com.seeyon.ctp.login.IdentificationDogLoginAuthentication | 使用身份验证狗认证 |
com.seeyon.apps.ldap.login.LDAPLoginAuthentication | 使用LDAP认证 |
com.seeyon.ctp.login.auth.DefaultLoginAuthentication | 使用协同用户系统认证 |
各验证器按顺序依次调用认证方法,只要有一个通过则该次登录认证通过。
要实现自己的登录认证,必须:
1 继承com.seeyon.ctp.login.AbstractLoginAuthentication,实现自己的登录验证类
package com.seeyon.apps.login;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.seeyon.ctp.common.constants.Constants;
import com.seeyon.ctp.common.constants.LoginConstants;
import com.seeyon.ctp.login.AbstractLoginAuthentication;
public class CustomLoginAuthentication extends AbstractLoginAuthentication {
@Override
public String[] authenticate(HttpServletRequest request,
HttpServletResponse response) throws LoginAuthenticationException {
String username = request.getParameter(LoginConstants.USERNAME);// 用户名
String password = request.getParameter(LoginConstants.PASSWORD);// 密码
if (username == null || password == null) {
return null;
}
//登录方式,判断是否移动应用登陆
String userAgentFrom = request.getParameter(Constants.LOGIN_USERAGENT_FROM);
boolean fromMobile = Constants.login_useragent_from.mobile.name().equals(userAgentFrom) || LoginUtil.isFromM1(userAgentFrom);
if (check(username, password)) {
return new String[] { username, password };
}
return null;
}
private boolean check(String username, String password) {
// 登录认证逻辑,用户名和密码正确时返回true即可
return false;
}
}
注册Spring bean
在插件的springxml文件中,增加
<bean class="com.seeyon.apps.login.CustomLoginAuthentication"/>
1.2. 登录认证拦截LoginInterceptor
对登录认证进行拦截
典型应用场景如下:
- 记录登录审计日志
- IP、浏览器控制
/**
* 登录之前的操作
*
* 此时AppContext.getCurrentUser()是null的
*
* @param request
* @param response
* @return Error标示本次登录终止,返回到登录页;OK正常往下进行
*/
public LoginResult preHandle(HttpServletRequest request, HttpServletResponse response);
/**
* 在登录验证成功后的操作
* 此时AppContext.getCurrentUser()有值
* @param request
* @param response
* @return Error标示本次登录终止,返回到登录页;OK正常往下进行
*/
public LoginResult afterComplete(HttpServletRequest request, HttpServletResponse response);
/**
* 在登录验证失败后的操作
*
* @param request
* @param response
* @return Error不管怎么样都会跳转到登录页面,最好别返回LoginResult.OK他也没有用
*/
public LoginResult afterFailure(HttpServletRequest request, HttpServletResponse response);
系统缺省通过几个拦截器实现一些功能控制
验证器 | 说明 |
---|---|
com.seeyon.ctp.login.interceptor.VerifyCodeLoginInterceptor | 验证码拦截器,在preHandle对用户输入的验证码进行校验 |
com.seeyon.ctp.login.interceptor.LockLoginInterceptor | 锁定用户拦截器 |
com.seeyon.ctp.login.interceptor.IpcontrolLoginInterceptor | IP控制拦截器 |
com.seeyon.ctp.login.interceptor.MutilBrowserLoginInterceptor | 限制管理员只能使用PC,通过IE登录 |
可以通过以下步骤实现登录拦截:
1 继承com.seeyon.ctp.login.AbstractLoginInterceptor,实现自己的登录拦截器类
package com.seeyon.apps.login;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.seeyon.ctp.common.constants.LoginConstants;
import com.seeyon.ctp.login.AbstractLoginInterceptor;
import com.seeyon.ctp.login.LoginAuthenticationException;
public class CustomMutilBrowserLoginInterceptor extends com.seeyon.ctp.login.AbstractLoginInterceptor {
public CustomMutilBrowserLoginInterceptor() {
}
//管理员只能通过IE、PC访问
public LoginResult afterComplete(HttpServletRequest request,HttpServletResponse response) {
User currentUser = CurrentUser.get();
if(currentUser.isAdmin()) {
Boolean A8Allow4Admin = (Boolean)(BrowserFlag.A8Allow4Admin.getFlag(request));
//管理员只能从IE上登录
if (Boolean.FALSE.equals(A8Allow4Admin)) {
return LoginResult.ERROR_IPCONTROLIPAD;
}
//管理员不能从M1上登录
if(currentUser.isFromM1() || Constants.login_useragent_from.mobile.name().equals(currentUser.getUserAgentFrom())){
return LoginResult.ERROR_ForbiddenAdminLogin;
}
}
return LoginResult.OK;
}
}
2 注册Spring bean
在插件的springxml文件中,增加
<bean class="com.seeyon.apps.login.CustomMutilBrowserLoginInterceptor"/>
1.3. 排序
在大多数场景下,同一套产品只会有一个主要的LoginAuthentication生效,而LoginInterceptor对顺序不敏感,原则上不需要排序。
但如果要对LoginAuthentication和LoginInterceptor进行排序,可以在插件目录定义一个login.xml,如(WEB-INF\cfgHome\plugin\myplugin\login.xml)
<?xml version="1.0" encoding="UTF-8"?>
<login>
<bean class="com.seeyon.apps.login.CustomLoginInterceptor" before="com.seeyon.ctp.login.interceptor.LockLoginInterceptor"/>
<bean class="com.seeyon.apps.login.CustomLoginAuthentication" after="com.seeyon.v3x.plugin.ca.CALoginAuthentication"/>
</login>
将CustomLoginInterceptor放到com.seeyon.ctp.login.interceptor.LockLoginInterceptor之前执行。
将CustomLoginAuthentication放到com.seeyon.v3x.plugin.ca.CALoginAuthentication之后执行。
一旦定义了login.xml,对应的bean就无需在spring xml中注册。
1.4. 使用平台认证登录
最简单的方式,是直接使用平台的登录
GET http://127.0.0.1/seeyon/main.do?login_username={loginName}&login_password={password}
然后获取响应的Header中的LoginOK,如果有值说明登录成功。
登录成功后获取Cookie,以后的请求都使用Cookie中的JSESSIONID发起即可。
但这样的方式与PC公用并发,会导致PC的登录被迫下线。
M1、M3和致信都是在后台重写了登录的入口,但这个是内部的实现,有很多控制。
对于移动应用认证,我们建议的开发方式是只通过用户密码校验的REST接口进行身份认证,使用REST接口开发
POST authentication?login_username={loginName}&login_password={password}
成功也会返回LoginOK,但不进行真实的登录。
1.5. 登录提示信息编码
编码 | 状态 | 备注 | 提示信息 |
---|---|---|---|
1001 | exceed_max_member | 超出并发数限制 | 超出了最大登录人数 |
1002 | exceed_max_member_in_account | 超出单位并发数限制 | 超出了您所在单位的最大登录人数 |
1003 | loginUserState.adminKickoff | 被管理员强制下线 | 您被管理员强制下线 |
1004 | LoginOfflineOperation.networkOff | 网路故障 | 网络故障,您被迫下线 |
1005 | loginUserState.changePassword | 其他端修改了密码 | 密码已被修改{0},请重新登录。 |
1006 | loginUserState.kickOff | 被其他端下线 | 您的账号已被下线! |
1007 | LoginOfflineOperation.loginAnotherone | 在另一个地点登录 | 您的帐号在另一地点登录,您被迫下线 |
1010 | loginUserState.unknown | 未知错误 | 被迫下线,原因:与服务器失去连接 |
1021 | 无效的用户名或密码 | ||
1022 | 无效的用户名或密码 该帐号仅剩下{0}次登录尝试机会 | ||
1023 | 账号被锁定,请稍后重试或联系管理员 | ||
1024 | 该帐号已经被禁用.请联系管理员. | ||
1031 | 您没有在符合的IP范围内登录 | ||
1041 | 管理员不能在该浏览器上登录 | ||
1042 | 管理员不能登录 | ||
1045 | 短信登录验证码不匹配或过期 | ||
1047 | 身份验证狗不可用。 | ||
1051 | 证书已过期。 | ||
1052 | 证书已吊销。 | ||
1053 | 证书被吊销且已过期。 | ||
1054 | 证书服务器错误,请联系管理员。 | ||
1055 | 证书与协同账号没有绑定,请联系管理员。 | ||
1056 | 此IP登录必须拥有账号所对应的CA证书 | ||
1057 | 请安装CA证书或插入CA硬件设备,请联系管理员 | ||
1058 | 此帐号和CA帐号绑定不正确,请联系管理员 | ||
1060 | 域用户验证失败 | ||
1061 | 域用户绑定信息不存在 |