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组 ...
随机推荐
- android笔记:Notification通知的使用
通知(Notification),当某个应用程序希望向用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知来实现. 发出一条通知后,手机最上方的状态栏中会显示一个通知的图标,下拉状态栏后 ...
- Linux下yum升级安装PHP 5.5
我的系统是Centos 6.5 ,安装lnmp是直接yum安装的,php版本为5.4的,当安装了最新的phpMyAdmin(4.5.1)数据库管理软件后发现不支持php5.4使用,所以只好升级下php ...
- jQuery easyui treegrid无法传参到后台bugger一记
$("#lTreegrid").treegrid("options").queryParams={id:123456,name:"Hai he&quo ...
- IOS 进度条与手势
//进度条#import "ViewController.h" @interface ViewController () { UIImageView* _animaImageV; ...
- Ubuntu设置squid代理
1.安装squid sudo apt-get install squid 2,修改配置,增加需要使用代理的ip vi命令修改: vi /etc/squid/squid.conf 图形界面编辑 sudo ...
- 【java】:生成excel
//生成报表公用方法 //excelName: 生成的文件名 //list:时间/日期/描述 //listSelectFiled: 标题 //showContent : 文件内容bean //生成 ...
- EasyUI 添加tab页(iframe方式)(转)
function addTab(title, href,icon){ var tt = $('#tabs'); if (tt.tabs('exists', title)){//如果tab已经存在,则选 ...
- (2015秋) 作业6:(电梯系统之结对编程 I 总分=2*50 分)
电梯系统 0. 背景 南通大学钟秀校区“主教学楼” 用 2 部电梯(连地下室共9层):每到下课.上课前都特别拥挤,大家希望改进已有的电梯调度算法,满足学生和老师快速乘坐电梯的需要.因此,需要重新设计一 ...
- 在NopCommerce中启用MiniProfiler
MVC MiniProfiler是Stack Overflow团队设计的一款对ASP.NET MVC.WebForm 以及WCF 的性能分析的小程序.可以对一个页面本身,及该页面通过直接引用.Ajax ...
- java中this用法总结
1,当局部变量和成员变量重名的时候,在方法中使用this表示成员变量以示区分. class Demo{ String str = "这是成员变量"; void fun(String ...