1. 为什么Fiori Launchpad的注销需要特别处理?
在标准SAP Fiori Launchpad实现中,点击右上角的注销按钮通常只会清除前端的会话信息,而不会彻底终止后端系统的认证会话。这就导致了一个安全隐患:用户可能误以为已经安全退出系统,但实际上通过直接访问URL仍能重新进入系统而不需要重新登录。
我曾在某制造企业项目中遇到过这样的场景:用户在公用电脑上使用Fiori系统后执行了注销操作,但下一位用户打开浏览器历史记录中的Fiori链接时,竟然直接进入了系统界面——这正是因为前用户的身份认证票据(如SAP Logon Ticket或OAuth Token)仍在有效期内。
2. 完整注销方案的技术架构
要实现真正完整的注销流程,需要协调三个层面的操作:
- 前端层面:清除浏览器存储的会话数据(localStorage/sessionStorage/cookies)
- 应用服务器层面:终止SAP Gateway/OData服务的会话
- 认证服务器层面:使SAP Logon Ticket或OAuth Token失效
这个过程中最关键的挑战在于SAP系统间的会话管理机制。SAP系统通常使用以下认证方式:
- SAP Logon Tickets(基于MYSAPSSO2 cookie)
- OAuth 2.0令牌(用于Fiori Launchpad与后端系统的通信)
- 基于浏览器的会话cookie(JSESSIONID等)
3. 自定义退出页面实现
3.1 创建自定义注销页面
在WebDispatcher的静态资源目录(如/sap/public/bc/static_content)下创建logout.html:
html复制<!DOCTYPE html>
<html>
<head>
<title>SAP系统已安全退出</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<script>
// 清除所有SAP相关cookie
document.cookie.split(";").forEach(function(c) {
var name = c.trim().split("=")[0];
if(name.startsWith("SAP") || name === "MYSAPSSO2"){
document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
}
});
// 清除本地存储
localStorage.clear();
sessionStorage.clear();
// 5秒后自动跳转
setTimeout(function(){
window.location.href = "https://yourcompany.com";
}, 5000);
</script>
</head>
<body>
<div style="text-align: center; margin-top: 100px;">
<h1>您已从SAP系统安全退出</h1>
<p>所有会话信息已清除,5秒后将跳转到公司主页</p>
<p>为确保安全,请关闭浏览器窗口</p>
</div>
</body>
</html>
3.2 配置Fiori Launchpad的登出URL
在Fiori Launchpad的配置文件中设置登出后跳转地址:
xml复制<!-- portal_desktop.properties -->
logout.redirect.url=/sap/public/bc/static_content/logout.html
4. 系统联动注销实现
4.1 后端系统会话终止服务
创建ABAP类实现会话终止功能:
abap复制CLASS zcl_session_terminator DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
CLASS-METHODS:
terminate_all_sessions
IMPORTING
iv_user TYPE sy-uname.
ENDCLASS.
CLASS zcl_session_terminator IMPLEMENTATION.
METHOD terminate_all_sessions.
DATA: lt_sessions TYPE TABLE OF t000.
" 获取用户所有活跃会话
SELECT * FROM t000 INTO TABLE lt_sessions
WHERE uname = iv_user.
" 终止每个会话
LOOP AT lt_sessions ASSIGNING FIELD-SYMBOL(<ls_session>).
CALL FUNCTION 'TH_DELETE_USER'
EXPORTING
user = iv_user
client = sy-mandt
tid = <ls_session>-tid.
ENDLOOP.
" 使SAP Logon Ticket失效
CALL FUNCTION 'SAPGUI_INVALIDATE_TICKET'
EXPORTING
user = iv_user.
ENDMETHOD.
ENDCLASS.
4.2 前端调用会话终止服务
在Fiori Launchpad的Component.js中扩展注销逻辑:
javascript复制sap.ui.define([
"sap/ushell/Container",
"sap/base/Log"
], function(Container, Log) {
"use strict";
var _originalLogout = Container.prototype.logout;
Container.prototype.logout = function() {
return new Promise(function(resolve, reject) {
// 调用自定义后端服务终止会话
$.ajax({
url: "/sap/opu/odata/sap/ZSESSION_SRV/TerminateAllSessions",
method: "POST",
headers: {
"X-CSRF-Token": Container.getRenderer("fiori2").getCSRFToken()
}
}).then(function() {
// 继续标准注销流程
_originalLogout.call(this).then(resolve).catch(reject);
}.bind(this)).catch(function(err) {
Log.error("Session termination failed: " + err.message);
// 即使失败也继续注销流程
_originalLogout.call(this).then(resolve).catch(reject);
}.bind(this));
}.bind(this));
};
});
5. SAP Web Dispatcher关键配置
5.1 修改规则配置
在WebDispatcher的配置目录下创建modification_rule.txt:
code复制# 强制注销时清除所有相关cookie
ResponseHeader modify Set-Cookie ^(.*SAP.*)$ "" override
ResponseHeader modify Set-Cookie ^(MYSAPSSO2=.*)$ "" override
# 拦截注销请求并转发到自定义处理程序
URL /sap/public/bc/icf/logoff -> /sap/public/bc/icf/custom_logoff
5.2 安全相关参数配置
在WebDispatcher的profile参数中设置:
code复制icm/HTTP/filter_headers = P3P, Server
icm/HTTP/security_headers = X-Frame-Options: DENY
icm/HTTP/security_headers += X-XSS-Protection: 1; mode=block
icm/HTTP/security_headers += X-Content-Type-Options: nosniff
icm/HTTP/security_headers += Strict-Transport-Security: max-age=31536000; includeSubDomains
# 会话超时设置(单位:秒)
login/accept_sso2_ticket = 600
login/ticket_expiration_time = 3600
login/create_sso2_ticket = 2
6. 常见问题与调试技巧
6.1 注销后仍能返回系统的问题排查
如果发现注销后通过浏览器后退按钮仍能返回系统,通常是因为:
-
浏览器缓存问题:在HTTP响应头中添加以下控制指令:
code复制Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Expires: 0 -
SAP Logon Ticket未失效:检查SICF服务
/sap/public/bc/icf/logoff是否被正确调用,使用ST01跟踪事务代码查看票证是否被加入黑名单。 -
OAuth Token仍有效:在网关系统使用事务代码/oauth2/clients检查令牌有效期设置,建议设置为较短时间(如30分钟)。
6.2 WebDispatcher配置验证
使用以下命令测试WebDispatcher规则是否生效:
bash复制# 检查当前生效的配置
sudo sapwebdisp -pf /usr/sap/WD1/profile/WD1_profile -show mod
# 测试URL重定向
curl -v -k "https://yourfiorisystem.com/sap/public/bc/icf/logoff"
7. 生产环境部署建议
-
分阶段实施:
- 开发环境:先测试自定义注销页面
- QA环境:加入系统联动注销
- 生产环境:最后配置WebDispatcher规则
-
监控设置:
- 在Solution Manager中创建特定监控点检查注销功能
- 设置警报规则,当注销失败率超过1%时触发通知
-
用户教育:
- 在注销页面添加明确的视觉提示
- 为新用户提供安全培训,强调完整注销的重要性
-
定期审计:
- 每月检查ICM日志中的注销请求
- 每季度进行安全测试,验证会话终止机制的有效性
我在实际项目中发现,最容易被忽视的是测试各种边缘场景:
- 多标签页同时打开Fiori时的注销行为
- 移动端Chrome浏览器的特殊缓存机制
- 通过书签直接访问深层链接时的会话状态
一个实用的技巧是在注销页面添加"立即关闭所有浏览器窗口"的JavaScript代码:
javascript复制// 尝试关闭窗口(可能被浏览器阻止)
try {
window.open('','_self').close();
} catch(e) {
console.log("Window close blocked by browser");
}
// 作为备选方案,显示强烈提示
document.getElementById("closeWarning").style.display = "block";
