Liferay7 BPM门户开发之32: 实现自定义认证登陆(定制Authentication Hook)
第一步:修改liferay-hook.xml
<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd"> <hook>
<portal-properties>portal.properties</portal-properties>
</hook>
如果是liferay7则不需要这一步,只需要注解:
@Component(
immediate = true, property = {"key=auth.pipeline.pre"},
service = Authenticator.class
)
第二步:配置认证属性portal.properties
auth.pipeline.pre=com.proliferay.YourAuthenticator
配置auth.pipeline.post 还将进行密码检查,liferay的内部机制是2级检查,一级是身份认证,二级是密码检查,实际上可以通过SKIP_LIFERAY_CHECK来统一处理
第三步:开发定制的认证类
import java.util.Map;
import com.liferay.portal.security.auth.AuthException;
import com.liferay.portal.security.auth.Authenticator; public class YourAuthenticator implements Authenticator { @Override
public int authenticateByEmailAddress(long companyId, String emailAddress,
String password, Map<String, String[]> headerMap,
Map<String, String[]> parameterMap) throws AuthException { /**
* 这里是认证的逻辑
*/ return SKIP_LIFERAY_CHECK;
} @Override
public int authenticateByScreenName(long companyId, String screenName,
String password, Map<String, String[]> headerMap,
Map<String, String[]> parameterMap) throws AuthException { return DNE;
} @Override
public int authenticateByUserId(long companyId, long userId,
String password, Map<String, String[]> headerMap,
Map<String, String[]> parameterMap) throws AuthException {
return DNE;
} }
常数定义:
- public static final int DNE = 0; //用户不存在
- public static final int FAILURE = -1;//认证失败
- public static final int SKIP_LIFERAY_CHECK = 2;
- public static final int SUCCESS = 1;
要注意SKIP_LIFERAY_CHECK和SUCCESS的区别,通过SKIP_LIFERAY_CHECK来统一处理身份认证,跳过门户的密码检查,如果返回SUCCESS,则必须配合auth.pipeline.post来进行密码检查。
通过图来说明:
一个具体的例子:
集成Apache Shiro的认证登陆
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.security.auth.AuthException;
import com.liferay.portal.kernel.security.auth.Authenticator; import java.util.Map; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory; import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component; @Component(
immediate = true, property = {"key=auth.pipeline.pre"},
service = Authenticator.class
)
public class ShiroAuthenticatorPre implements Authenticator { @Activate
public void activate() {
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:userauth.ini"); //shiro配置文件 SecurityUtils.setSecurityManager(factory.getInstance()); if (_log.isInfoEnabled()) {
_log.info("activate");
}
} @Override
public int authenticateByEmailAddress(
long companyId, String emailAddress, String password,
Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
throws AuthException { if (_log.isInfoEnabled()) {
_log.info("authenticateByEmailAddress");
} UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
emailAddress, password); Subject currentUser = SecurityUtils.getSubject(); try {
//shiro的代理登陆
currentUser.login(usernamePasswordToken); boolean authenticated = currentUser.isAuthenticated(); if (authenticated) {
if (_log.isInfoEnabled()) {
_log.info("authenticated");
} return SKIP_LIFERAY_CHECK; //认证通过
}
else {
return FAILURE;
}
}
catch (AuthenticationException ae) {
_log.error(ae.getMessage(), ae);
throw new AuthException(ae.getMessage(), ae);
}
} @Override
public int authenticateByScreenName(
long companyId, String screenName, String password,
Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
throws AuthException { if (_log.isInfoEnabled()) {
_log.info("authenticateByScreenName - not implemented ");
} return SUCCESS;
} @Override
public int authenticateByUserId(
long companyId, long userId, String password,
Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
throws AuthException { if (_log.isInfoEnabled()) {
_log.info("authenticateByScreenName - not implemented ");
} return SUCCESS;
} private static final Log _log = LogFactoryUtil.getLog(
ShiroAuthenticatorPre.class); }
apache shiro框架结构
apache shiro是一套非常著名的安全框架,提供了认证、授权、加密和会话管理功能
了解更多apache shiro的知识:http://www.infoq.com/cn/articles/apache-shiro
Authentication的Token令牌机制
了解更多Authentication Token:https://web.liferay.com/zh/community/wiki/-/wiki/Main/Authentication+Token
Token令牌是为了避免CSRF跨站伪造。
了解更多CSRF:https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
定义认证失败的扩展处理
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.security.auth.AuthException;
import com.liferay.portal.kernel.security.auth.AuthFailure;
import com.liferay.portal.kernel.service.UserLocalServiceUtil;
import java.util.Map;
import org.osgi.service.component.annotations.Component; @Component(
immediate = true, property = {"key=auth.failure"},
service = AuthFailure.class
)
public class LogAuthFailure implements AuthFailure { @Override
public void onFailureByEmailAddress(
long companyId, String emailAddress,
Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
throws AuthException { try {
User user = UserLocalServiceUtil.getUserByEmailAddress(
companyId, emailAddress); int failures = user.getFailedLoginAttempts(); if (_log.isInfoEnabled()) {
_log.info(
"onFailureByEmailAddress: " + emailAddress +
" has failed to login " + failures + " times");
}
}
catch (PortalException pe) {
}
} @Override
public void onFailureByScreenName(
long companyId, String screenName, Map<String, String[]> headerMap,
Map<String, String[]> parameterMap)
throws AuthException { try {
User user = UserLocalServiceUtil.getUserByScreenName(
companyId, screenName); int failures = user.getFailedLoginAttempts(); if (_log.isInfoEnabled()) {
_log.info(
"onFailureByScreenName: " + screenName +
" has failed to login " + failures + " times");
}
}
catch (PortalException pe) {
}
} @Override
public void onFailureByUserId(
long companyId, long userId, Map<String, String[]> headerMap,
Map<String, String[]> parameterMap)
throws AuthException { try {
User user = UserLocalServiceUtil.getUserById(userId); int failures = user.getFailedLoginAttempts(); if (_log.isInfoEnabled()) {
_log.info(
"onFailureByUserId: userId " + userId +
" has failed to login " + failures + " times");
}
}
catch (PortalException pe) {
}
} private static final Log _log = LogFactoryUtil.getLog(LogAuthFailure.class); }
优秀的平台必然松耦合、易扩展。
Liferay7 BPM门户开发之32: 实现自定义认证登陆(定制Authentication Hook)的更多相关文章
- Liferay7 BPM门户开发之37: Liferay7下的OSGi Hook集成开发
hook开发是Liferay客制扩展的一种方式,比插件灵活,即可以扩展liferay门户,也能对原有特性进行更改,Liferay有许多内置的服务,比如用hook甚至可以覆盖Liferay服务. 可作为 ...
- Liferay7 BPM门户开发之17: Portlet 生命周期
Portlet 生命周期 init() =〉 render() =〉 processAction() =〉 processEvent() =〉 serveResource() =〉destroy() ...
- Liferay7 BPM门户开发之10: 通用流程实现从Servlet到Portlet(Part1)
开发目的: 实现通用流程自动化处理(即实现不需要hardcode代码的bpm统一处理后台,仅需要写少量前端html form代码和拖拽设计BPM定义) 既可独立运行或可依托于Liferay或依托其它门 ...
- Liferay7 BPM门户开发之26: 集成Activiti到Liferay7
开发顺序: 实战任务1,开发BPM管理后台(用于在Liferay管理中心管理Activiti模型上传) 一个熟悉Portlet操作的项目,为开发打好基础. http://www.cnblogs.com ...
- Liferay7 BPM门户开发之12:acitiviti和liferay用户权限体系集成
写到第12章才出现Liferay的内容,希望可以厚积薄发. 我们的目标是不使用不维护Activiti的用户组织架构,只维护Liferay的体系,这样的好处是非常明显的,即不用做组织架构的同步工作. 原 ...
- Liferay7 BPM门户开发之46: 集成Activiti用户、用户组、成员关系同步
在实际的BPM集成开发过程中,Liferay和Activiti这两个异构的系统之间,用户.组的同步需求非常重要,用来实现签收组的概念,比如指定签收组.会签.抢签都需要用到. Activiti可以通过自 ...
- Liferay7 BPM门户开发之20: 理解Asset Framework
Asset框架用于将您开发的门户内容添加Liferay的核心系统功能.打个比方,你开发了一个事件TodoList管理的插件,在列表显示的时候,你可以集成Asset框架,让你的自定义内容支持Tag标签. ...
- Liferay7 BPM门户开发之19: 理解Service Builder体系
Service Builder是Liferay为业务开发而设计的模型驱动(model-driven)平台工具,提供一系列的实体类.数据持久化.服务相关的代码自动生成服务.支持Hibernate and ...
- Liferay7 BPM门户开发之15: Liferay开发体系简介
Liferay SDK 开发体系 主要分6种: Portlet Hook Theme Layout Templates Web Modules Ext Portlet :类似于servlet的web组 ...
随机推荐
- .NET实现高效过滤敏感查找树算法(分词算法):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- VirtualBox中的虚拟机要如何设置,才能够上网
VirtualBox中有4种网络连接方式:1. NAT2. Bridged Adapter3. Internal4. Host-only Adapter 一般设置成NAT网路就可以,但是由于我在公司上 ...
- subprocess添加超时功能
def TIMEOUT_COMMAND(command, timeout): """call shell-command and either return its ou ...
- python学习笔记-Day6(1)
shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式 >>> s=shelve.open('test') > ...
- sublime使用以及快捷键
1.工程文件中的内容的查找替换 例: 想要把工程文件中的“山东”改为“云南”. 1)首先选中工程文件夹 2)右击出现下拉菜单,选择 find&replace 选项 3)出现在编辑框内输入要查找 ...
- HDU 1394Minimum Inversion Number 数状数组 逆序对数量和
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- cinder backup
cinder 备份提供的驱动服务有: cinder/backup/drivers/ceph.py:def get_backup_driver(context): cinder/backup/drive ...
- 【转】HTTP状态码(HTTP Status Code)
原文链接:http://www.chaoji.com/features/httpstatus.aspx 一些常见的状态码为: 200 - 服务器成功返回网页 404 - 请求的网页不存在 503 - ...
- win8 下 IIS APPPOOL\DefaultAppPool 登录失败的解决方法
来源:网络 添加ASP.NET网站时,选择添加"添加应用程序"连接sql server 2005(2008)可能会报始下的错误:(说明:2005必报错,2008选报错)" ...
- Python-pycharm
进入博客园的第一篇随笔,作为一个编程菜鸟,最近在学习Python,为毕设做准备.总觉得Python自带的idle不太好用,一位“大鸟”向我推荐了pycharm,于是我就抱着试试看的态度下了一个,目前感 ...