目录
snowy开源版本拉取:
springboot与camunda版本对比:
camunda7.15版本相关依赖,引入snowy-main中的pom文件:
snowy父pom将spring-boot-starter-parent版本进行(选择性)修改为2.4.3
yaml camunda的账户配置(选择性)
SnowyApplication启动类进行修改,添加camunda注解@EnableProcessApplication
将camunda接口相关权限放开SpringSecurityConstant:
启动后端,访问地址:http://localhost:82/camunda/app/welcome/default/#!/login
接管小诺放行的请求,开启camunda的请求拦截(鉴权):
sso自动登录
自动登录测试
对camunda的鉴权进行自定义(选择性使用)
放行camunda请求的,请求头校验
camunda鉴权开启效果
camunda web页面开启汉化
嵌入式表单位置:/resources/static/forms
-
snowy开源版本拉取:
Snowy: Snowy基于SpringBoot+AntDesignVue的前后分离全新RBAC权限管理系统,适配国产数据库(金仓、达梦)、主流数据库Mysql、Oracle、Mssql、Postgresql,小诺一致追求简洁干净,一套代码搞定!支持国产中间件部署、麒麟操作系统、Windows、Linux部署使用,另外支持saas多租户、flowable工作流、多数据源、支付模块等,更多插件正在扩展中。https://gitee.com/xiaonuobase/snowy
-
springboot与camunda版本对比:
Spring Boot Version Compatibility | docs.camunda.orgdocumentation of the Camunda Platformhttps://docs.camunda.org/manual/7.15/user-guide/spring-boot-integration/version-compatibility/
-
camunda7.15版本相关依赖,引入snowy-main中的pom文件:
org.camunda.bpm.springboot
camunda-bpm-spring-boot-starter-rest
7.15.0
org.camunda.bpm.springboot
camunda-bpm-spring-boot-starter-webapp
7.15.0
org.camunda.bpm
camunda-engine-plugin-spin
7.15.0
org.camunda.spin
camunda-spin-dataformat-all
1.11.0
-
snowy父pom将spring-boot-starter-parent版本进行(选择性)修改为2.4.3
org.springframework.boot spring-boot-starter-parent2.4.3
-
yaml camunda的账户配置(选择性)
如果不进行配置,那么在你登录的camunda官方提供的web页面时,camunda也会要求你初始化一个超级管理员的账户
camunda.bpm.admin-user: id: admin password: admin
-
SnowyApplication启动类进行修改,添加camunda注解@EnableProcessApplication
// 防止过滤器创建报空指针异常(2-1)(springSecurityConstant需要放开路径:"/camunda/api/engine")
@EnableProcessApplication
@SpringBootApplication
public class SnowyApplication {……}
-
将camunda接口相关权限放开SpringSecurityConstant:
public interface SpringSecurityConstant {
String[] NONE_SECURITY_URL_PATTERNS = {
……
// modeler 流程部署接口
"/engine-rest
@Configuration
public class CamundaSecurityFilter {
@Bean
public FilterRegistrationBean processEngineAuthenticationFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean<>(new ProcessEngineAuthenticationFilter());
// registration.setName("camunda-auth");
// registration.setFilter(new ProcessEngineAuthenticationFilter());
// camunda官方提供的鉴权(推荐)
registration.addInitParameter("authentication-provider",
"org.camunda.bpm.engine.rest.security.auth.impl.HttpBasicAuthenticationProvider");
// 根据camunda官方提供的鉴权进行改写(如果自己的系统不需要访问官方的接口,那么推荐使用camunda的鉴权)
// processEngineAuthenticationFilterRegistrationBean.addInitParameter("authentication-provider",
// "vip.xiaonuo.camunda.common.auth.provider.CamundaAuthenticationProvider");
registration.addUrlPatterns("/engine-rest
@Configuration
public class CamundaSecurityConfig {
// ContainerbasedAuthenticationFilter、ContainerbasedAuthenticationProvider
@Bean
public FilterRegistrationBean containerbasedAuthenticationFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean<>();
registration.setName("camunda-auth");
registration.setFilter(new AutoLoginAuthenticationFilter());
registration.addUrlPatterns("/camunda/app
public class AutoLoginAuthenticationFilter implements Filter {
private static final String[] APPS = new String[] { "cockpit", "tasklist", "admin", "welcome" };
@Override
public void init(FilterConfig arg0) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest req = (HttpServletRequest) request;
// get authentication from session
Authentications authentications = Authentications.getFromSession(req.getSession());
// This function is added to the normal AuthenticationFilter
setAutoLoginAuthentication(request, authentications);
// set current authentication to the one restored from session (maybe
// auto login was added)
Authentications.setCurrent(authentications);
try {
SecurityActions.runWithAuthentications(new SecurityAction() {
@Override
public Void execute() {
try {
chain.doFilter(request, response);
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
}, authentications);
} finally {
Authentications.clearCurrent();
// store updated authentication object in session for next request
Authentications.updateSession(req.getSession(), authentications);
}
}
protected void setAutoLoginAuthentication(final ServletRequest request, Authentications authentications) {
final HttpServletRequest req = (HttpServletRequest) request;
final ProcessEngine engine = getEngine();
// Get the username from the user in SSO
String username = retrieveUsername(req);
// if not set - no auto login
if (username == null) {
return;
}
// if already in the list of logged in users - nothing to do
Authentication authentication = authentications.getAuthenticationForProcessEngine(engine.getName());
if (authentication != null && authentication.getName() == username) {
return;
}
AuthorizationService authorizationService = engine.getAuthorizationService();
// query group information
List groupIds = getGroupsOfUser(engine, username);
List tenantIds = getTenantsOfUser(engine, username);
// check user's app authorizations by iterating of list of apps and ask
// if permitted
HashSet authorizedApps = new HashSet();
authorizedApps.add("admin");
if (engine.getProcessEngineConfiguration().isAuthorizationEnabled()) {
for (String application : APPS) {
if (authorizationService.isUserAuthorized(username, groupIds, ACCESS, APPLICATION, application)) {
authorizedApps.add(application);
}
}
} else {
Collections.addAll(authorizedApps, APPS);
}
// create new authentication object to store authentication
UserAuthentication newAuthentication = new UserAuthentication(username, engine.getName());
newAuthentication.setGroupIds(groupIds);
newAuthentication.setTenantIds(tenantIds);
newAuthentication.setAuthorizedApps(authorizedApps);
// and add the new logged in user
authentications.addAuthentication(newAuthentication);
}
protected String retrieveUsername(final HttpServletRequest req) {
// Simply read it from a URL parameter in this case
return req.getParameter("auto-login-username");
}
protected List getGroupsOfUser(ProcessEngine engine, String userId) {
List groups = engine.getIdentityService().createGroupQuery().groupMember(userId).list();
List groupIds = new ArrayList();
for (Group group : groups) {
groupIds.add(group.getId());
}
return groupIds;
}
protected List getTenantsOfUser(ProcessEngine engine, String userId) {
List tenants = engine.getIdentityService().createTenantQuery().userMember(userId).includingGroupsOfUser(true).list();
List tenantIds = new ArrayList();
for (Tenant tenant : tenants) {
tenantIds.add(tenant.getId());
}
return tenantIds;
}
private ProcessEngine getEngine() {
// TODO: only works in single engine environment!
return BpmPlatform.getDefaultProcessEngine();
}
}
-
自动登录测试
http://localhost:82/camunda/app/welcome/?auto-login-username=admin
-
对camunda的鉴权进行自定义(选择性使用)
如果自己的系统要直接访问camunda官方提供的接口,那么就需要对camunda的鉴权进行自定义,可参考以下内容:
package vip.xiaonuo.camunda.common.auth.provider;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.impl.digest._apacheCommonsCodec.base64;
import org.camunda.bpm.engine.rest.security.auth.AuthenticationProvider;
import org.camunda.bpm.engine.rest.security.auth.AuthenticationResult;
import org.springframework.util.StringUtils;
import vip.xiaonuo.core.context.login.LoginContextHolder;
import vip.xiaonuo.core.pojo.login.SysLoginUser;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.HttpHeaders;
public class CamundaAuthenticationProvider implements AuthenticationProvider {
protected static final String BASIC_AUTH_HEADER_PREFIX = "Basic ";
protected static final String TOKEN_TYPE_BEARER = "Bearer";
@Override
public AuthenticationResult extractAuthenticatedUser(HttpServletRequest request, ProcessEngine engine) {
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authorizationHeader != null) {
if(authorizationHeader.startsWith(BASIC_AUTH_HEADER_PREFIX)){
String encodedCredentials = authorizationHeader.substring(BASIC_AUTH_HEADER_PREFIX.length());
String decodedCredentials = new String(base64.decodebase64(encodedCredentials));
int firstColonIndex = decodedCredentials.indexOf(":");
if (firstColonIndex != -1) {
String userName = decodedCredentials.substring(0, firstcolonIndex);
String password = decodedCredentials.substring(firstColonIndex + 1);
if (isAuthenticated(engine, userName, password)) {
return AuthenticationResult.successful(userName);
}
}
}
if(authorizationHeader.startsWith(TOKEN_TYPE_BEARER)){
SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUser();
// AuthService authService = SpringUtil.getBean(AuthService.class);
User user = engine.getIdentityService().createUserQuery().userId(sysLoginUser.getAccount()).singleResult();
if(!StringUtils.isEmpty(user)){
return AuthenticationResult.successful(user.getId());
}
}
}
return AuthenticationResult.unsuccessful();
}
protected boolean isAuthenticated(ProcessEngine engine, String userName, String password) {
return engine.getIdentityService().checkPassword(userName, password);
}
@Override
public void augmentResponseByAuthenticationChallenge(
HttpServletResponse response, ProcessEngine engine) {
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, BASIC_AUTH_HEADER_PREFIX + "realm="" + engine.getName() + """);
}
}
-
放行camunda请求的,请求头校验
camunda开启鉴权后,官方的web请求会在请求头中携带authorization且以Basic作为开头,目前很多国内的系统,在鉴权的过程中,大部分都是先判断请求头中的是否含有authorization,如果有那么就判断是头是以Bearer作为开头,如果不是的话,那么就认为该请求头不符合规范,返回给前端;所以要想camunda的接口能够正常使用,那么就需要对框架中的这部分逻辑进行改进,以小诺框架为例,可参考以下内容:
注意这是一个坑:camunda的流程设计器,在鉴权未开启时,请求头中的authorization也会携带内容传递给后端,此时携带的内容为“undefined”字符串,针对这种情况,后端在针对这种情况时,也要进行放行
@Override
public String getTokenFromRequest(HttpServletRequest request) {
String authToken = request.getHeader(CommonConstant.AUTHORIZATION);
// 放行camunda以Basic开头的请求头
if (ObjectUtil.isEmpty(authToken) || CommonConstant.UNDEFINED.equals(authToken)||authToken.startsWith(CommonConstant.TOKEN_TYPE_BASIC)) {
return null;
} else {
//token不是以Bearer打头,则响应回格式不正确
if (!authToken.startsWith(CommonConstant.TOKEN_TYPE_BEARER)) {
throw new AuthException(AuthExceptionEnum.NOT_VALID_TOKEN_TYPE);
}
try {
authToken = authToken.substring(CommonConstant.TOKEN_TYPE_BEARER.length() + 1);
} catch (StringIndexOutOfBoundsException e) {
throw new AuthException(AuthExceptionEnum.NOT_VALID_TOKEN_TYPE);
}
}
return authToken;
}
-
camunda鉴权开启效果
- 流程设计器发生的变化:
Download The Camunda BPMN / DMN Process Modeler | CamundaA free and easy-to-use desktop app for editing BPMN Process Diagrams, DMN Decision Tables, and Forms. Camunda Modeler supports BPMN 2.0 and DMN 1.3.https://camunda.com/download/modeler/部署请求地址:http://localhost:82/engine-rest
- camunda官方web发生的变化:
此时再访问后端的接口在未登录的情况下访问:http://localhost:82/camunda/api/engine/engine/default/task/43483a51-2524-11ec-9fe5-861b7790c7c0
会出现如下效果:
-
camunda web页面开启汉化
camunda7.15版本汉化_camunda汉化-企业管理文档类资源-CSDN下载camunda7.15版本汉化camunda汉化更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/weixin_44213308/21481004目录结构如下:
除了cockpit,admin和task,都汉化过了,注意:汉化区分版本7.14版本的汉化过程与7.15版本是有区别的,这是7.15版本的汉化过程。
效果如下:
-
嵌入式表单位置:/resources/static/forms
具体使用方式,参考:
的博客-CSDN博客">camunda集成系列教程3-嵌入式表单_<每天一点>的博客-CSDN博客https://docs.camunda.org/manual/latest/user-guide/task-forms/#camunda-forms首先,camunda平台的表单分为三种:1、嵌入式任务表单允许您将自定义 HTML 和 Javascript 表单嵌入到任务列表中。2、Camunda Forms在 Camunda Modeler 中提供表单的可视化编辑,可用于不太复杂的表单。3、外部任务表单可用于链接到自定义应用程序。表单不会嵌入到任务列表中。首先在了解表单之前,我们先了https://blog.csdn.net/weixin_44213308/article/details/119715559



