Oinone
Products
Oinone
Oinone Framework
Enterprise Low-code Framework
Aino
Aino
Intelligent AI Platform
Use CasesPricingBlogCommunity
Resources
📖
Documentation
Guides and API References
💬
Support
Get Technical Support
📄
Changelog
Latest Release Notes
🏡
About
Our Team and Vision
Search K
v6.xv7.x
简体中文English
Installation and Upgrade
Community Edition
Enterprise Edition
Transition from Community Edition to Enterprise Edition
Oinone Designer Configuration Guide
Version Upgrade
Version List
FAQ
Dev Manual
Tutorials
Dev ENV
Git Setup
JDK Setup
Maven Setup
Node.js Setup
Setup Guide
Back-end Framework
Chapter 1:Architecture Overview
Chapter 2:A New Application
Chapter 3:Models And Basic Fields
Chapter 4:A Brief Introduction To Security
Chapter 5:Finally, Some UI To Play With
Chapter 6:Basic Views
Chapter 7:Relations Between Models
Chapter 8:Field Interlinkage
Chapter 9:Ready For Some Action
Chapter 10:Constraints
Chapter 11:Add The Sprinkles
Chapter 12:Inheritance
Chapter 13:Interact With Other Modules
Chapter 14:Customized Features
Discover the Front-end Framework
Chapter 1:Widget
Chapter 2:Build a Dashboard
Master the Front-End Framework
Chapter 1:Front-End Overview
Chapter 2:Create a Gantt View
Chapter 3:Customize a Gallery View
Init Module Data
Restrict Access to Data
Export and Import
Debug Tools
Operation Guide
Customize a Field Widget
Customize a action widget
Customize a view widget
Customize GraphQL Requests
Customize Themes
Default Themes
Dark Themes
Combination Of Customized Widget And Designer
Reference Guide
Back-End framework
Module API
ORM API
Functions API
Actions API
UX API
Security in Oinone
Advance API
Protocol API
Request Context API
Meta Directive API
Hint API
Message Hub API
FileClient API
MQ API
Redis API
ES API
Tools API
Front-End framework
Framework Overview
Environment
Context
Widget
Component Lifecycle
Basic
Mask
Layout
DSL
View
Element
Pack
Action
Field
Table Field
Search Field
Form Field
Detail Field
Gallery Field
Router
Oio Components
Vue UI Antd
Vue UI El
Vue UI
Services
Metadata Service
SPI Service
Router Service
GraphQL Service
HttpClient Service
RSQL Service
Message Hub Service
Event Bus Service
Stream Service (peer to peer)
Expression Service
Translate Service
User interface
View architectures
Table
Form
Detail
Gallery
Tree
UI icons
Standard Modules
User & Business API
Message API
Workflow
Import and Export
Resources API
EIP API
Common Extension Points And SPI List
Error Codes
R&D Paradigm
R&D Paradigm:R&D Process
R&D Paradigm:Modular Design
R&D Paradigm:Model Design
Software Companies:The Paradigm of Standardization and Customization Symbiosis
Common Solutions
Frontend
Global Layout:Custom Tree Component with Default First Value Selection
Release:Frontend Release Process
Field:How to Automatically Refresh Views When Switching Between Multi-Tabs
Field:Data Pop-Back from Popup Operations to Fields
Application:Embedding as Iframe into Existing Systems
Application:Introducing Qiankun Micro-Frontend
Button:How to Display Workflow Approval Buttons in Business Model Lists
Button:Passing Extra Parameters Across Pages
Network Requests:Detailed Explanation of OioProvider (Custom Request Error Interception)
Network Requests:Request Encryption
Views:Implementing Multiple View Switching
Views:Table Column Merging
Views:Table Column Footer Statistics
Views:Table Row Copy Functionality
Route Extension:Adding New Routes, such as Overriding the Default Login Page
Backend
Dependency Configuration:How to Add Data Visualization Runtime Dependencies
Feature Introduction:Data Visualization - How to Reference Charts, Reports, and Dashboards in Projects
Visual Construction:Low-Code and No-Code Integration for Charts in Data Visualization
Visual Query:Data Visualization - How to Customize Query Data Methods
Scenario Application:Excel Watermark Addition Functionality
Scenario Application:Asynchronous Execution of Functions
Scenario Application:Dynamic Forms (Same Button Jumps to Different Pages)
External Integration:Enterprise WeChat OAuth2.0 Integration
External Integration:DingTalk Integration with OAuth2.0
Sequence Acquisition:How to Manually Obtain Sequences in Projects
Development Mode:Collaborative Development (Revised)
Development Specifications:Function and Action Function Usage Specifications
Development Aid:Configuration Issues and Troubleshooting Paths for O2M, M2O, and M2M Relationship Fields
Development Assistance:Oinone Platform Visual Debugging Tool
Development Aid:Implementing Page Data Linkage in Low-Code
Development Aid:Implement Duplication Creation in Low-code Manner
Development Aid:Generating API Documentation with GraphQL
Development Aid:Automatic Form Filling with User-related Information
Release Process:Back-end release process
Development practice:Business implementation of a multi-tenant solution
Open Interface:EIP Open Interface Request with MD5 Signature
Search Enhancement:Oinone Introduces Search Engine (Enhanced Model)
Data Operation:DsHint(Specify Data Source) and BatchSizeHint(Specify Batch Quantity)
Search Enhancement:Common Problem Solutions for Introducing Search Enhancement Model Channel
Data Operation:Excel Import/Export Template Translation
Data Operation:Batch Excel Import
Data Operation:Usage of IWrapper, QueryWrapper, and LambdaQueryWrapper
Data Operation:Oinone External Data Source Connection Solution
Data Operation:Database and Table Sharding with Custom Sharding Rules
Data Operation:Complex Excel Template Definition
Data Operations:Import and Export of Complex Field Types
Data Operation:Multi-Sheet Import and Export Example
Data Operation:Multi-table Join Query Solutions
Data Operation:How to Use Bitwise Operation Data Dictionary
Data Operation:How to Customize Excel Import and Export Functions
Data Operation:Custom Sort Fields and Sorting Rules During Query
Data Operations:Custom RSQL Placeholders and Their Usage in Permissions
Data Operations:Custom SQL (Mapper) Statements
Data Operation:Unstored Field Search
Data Dialect:[DM] Backend Deployment with Dameng Database
Data Dialect:【KDB】Using Kingbase Database (Renmin Kingbase/KE Kingbase) for Backend Deployment
Data Dialect:[MSSQL] Backend Deployment with MSSQL Database (SQL Server)
Data Dialect:【OpenGauss】Using OpenGauss Database for Backend Deployment
Data Dialect:[PostgreSQL] Backend Deployment with PostgreSQL Database
File Storage:OSS Configuration for MINIO Without Public Network Access
File Storage:OSS (CDN) Configuration and File System Operations
Permission Extension:How to Skip Permission Interception for Functions
Permission Extension:How to Delete the Default Homepage Node in System Permissions
Permission Extension:How to Extend Action Permissions
Permission Extension:How to Add Menu Permissions to Roles
Permission Extension:How to Skip Fixed Path Permissions
Tree-Table Configuration:How to Configure Tree-Tables
Validation Customization:How to Implement Special Requirements with Custom Expressions? Extending Built-in Function Expressions
Process Extension:How to Add Workflow Runtime Dependencies
Process Extension:Workflow Audit Withdrawal, Rollback, and Rejection Hook Usage
Process expansion:Operate the workflow through business data (such as urging, canceling, etc.)
Process Extension:Summary of Custom Function Example Codes for Workflow Extension
Process Configuration:Workflow Introduction and Process Triggering in Projects
Message Customization:How to Push Custom Messages
Source Code Configuration:How to Configure Expressions Using Source Code
Environmental Protection:Oinone Environmental Protection (above v5.2.3)
Environment Upgrade:Cache Connection Switched from Jedis to Lettuce
Environment Deployment:Deploying Oinone Projects on TongWeb and Tomcat
Environment Deployment:Deploy Designer on NeoKylin (mips64 Architecture)
Environment Deployment:Backend No-Code Designer Jar Package Startup Method
Login Extension:Oinone Login Extension:Docking with SSO
Development Framework:Framework MessageHub(Information Prompt)
Network Request:Forced Password Change on First Login
Auto-increment ID:How to Use Auto-increment IDs in Projects
Authentication Integration:Single Sign-On (SSO)
Configuration Instructions:Detailed Dubbo Configuration (Revised)
Configuration Guide:Function Trigger and Scheduling Configuration with Examples
Page Design:Configuration Methods for Global Home and Application Home Pages (homepage)
Page Design:How to Achieve Page Navigation
Page Design:Customizing User Center Menu
Project Integration:Nacos as a Registration Center:How to Invoke SpringCloud Services of Other Systems?
Project Integration:How Oinone Supports Building Distributed Projects
Project Integration:Introducing Nacos as the Registration Center in Oinone Projects
Project Deployment:Common Issues in Docker Deployment
Project Deployment:Oinone Offline Deployment of Designer JAR Package
Project Deployment:Oinone Offline Deployment of Designer Image
Project Deployment:Oinone Designer Deployment Parameter Instructions
Project Deployment:Import and Export of Data Visualization
Project Deployment:Import and Export of Workflow Designer
Project Deployment:Import and Export of UI Designer
FAQ
Startup:Common Issues with Oinone License Usage
Startup:Issues with Startup Dependency Errors
Startup:Scheduling Server Unassigned Task Queue Keeps Logging Continuously
Startup:Common Issues with Backend Startup
How to Configure Multi-value Fields and Field Default Values During Development
How to Obtain the Requested Model During Development
Under Development:Model Copy Tool Class
How to Create Indexes, Unique Indexes, and Composite Indexes During Development
How to Obtain Current Logged-in User Information During Development
Environment Preparation:npm Installation Dependencies on Windows Environment Prompt Insufficient Permissions
Environment Migration:Dubbo Timeout Causes Import Failure When Importing Design Data
Operation and Maintenance Related:Does the Platform Have a Health Check Interface?
Runtime:Dubbo Service Not Found
Runtime:SQL Execution Error When Saving Multivalue Fields
Runtime:How to Properly Initiate Requests Using GQL Tools
Runtime:How to Implement Synchronous Excel Download
Runtime:Export Task Stuck in "Processing" State
Runtime:Field Not Found - Unknown field ‘xx’
Runtime:Permission Configuration Not Taking Effect
Runtime:Unable to Select Models in Interface Designer
Runtime:Troubleshooting "No Permission" Errors in Navigation Actions
Runtime:Context Parameters Configured but Values Not Passed to Redirected Page
AI Coding Practical Combat
Best Practices of AI Coding When Oinone Meets Trae (Backend)
Best Practices of AI Coding When Oinone Meets Qoder (Backend)
User Manual
Designer
Model Designer
Model
Data Dictionary
Data Coding
UI Designer
View Management
View Type
View Design
Widgets And Model Overview
Components
Layout
Fields
Media
Actions
Customized Components
Customized Component Management
Meta of Customized Component
Design of Customized Component Meta
Application Menu
Print Template Management
Print Template Design
Workflow Designer
Workflow Management
Workflow Design
Node Actions
Data Visualization
Chart Management
Chart Types
Chart Design
Reports
Data Dashboard Management
Data Dashboard Design
Chart Template
Integrated Designer
Workbench
Connector
Data Workflow
Workflow Logs
Open Platform
MCP
Business Domain
Api Logs
Microflow Designer
Microflow Management
Microflow Design
AI Integrated Designer
Connector
AI Workflow
Api Logs
Expressions Guide
Standard Modules
Workbench
Profile
Preferences
Administration Center
Users
Partners
Organization
Role and Permission
Workflow
Workflow
Workflow Management
Message
Business Audit
Files
Resources
Translation
Integration App
Apps Hub
Apps ENV
Low-Code No-Code Integration
Contribution Manual
CLA
R&D Contribution
Git Guidelines
Coding Guidelines
Documentation Contribution
Content Guidelines
Third-Party Open-Source Software and License Notice
Software Licenses and Agreements
  1. Home/
  2. Dev Manual/
  3. Common Solutions/
  4. Backend/
  5. Login Extension:Oinone Login Extension:Docking with SSO
On this page

Ⅰ、Overview ​

In an enterprise internal environment, if a complete Single Sign-On (SSO) system has been built, it is often required to integrate all internal systems into this SSO system based on considerations of improving enterprise information management efficiency and user experience. This article focuses on explaining the specific implementation methods and steps for projects developed using Oinone to dock with the SSO system.

Ⅱ、Docking Steps ​

  1. The project customizes the implementation of UserCookieLogin, which can refer to the example: pro.shushi.pamirs.user.api.login.UserCookieLoginFree

  2. Example of docking with SSO

java
package pro.shushi.pamirs.demo.core.sso;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import pro.shushi.pamirs.demo.core.sso.constant.HttpConstant;
import pro.shushi.pamirs.demo.core.sso.constant.SessionUserTypeEnum;
import pro.shushi.pamirs.demo.core.sso.model.ApiCommonTransient;
import pro.shushi.pamirs.demo.core.sso.model.PermissionInfoResp;
import pro.shushi.pamirs.demo.core.sso.utils.AuthenticateUtils;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO;
import pro.shushi.pamirs.meta.api.session.PamirsSession;
import pro.shushi.pamirs.meta.common.exception.PamirsException;
import pro.shushi.pamirs.meta.common.spring.BeanDefinitionUtils;
import pro.shushi.pamirs.resource.api.enmu.UserSignUpType;
import pro.shushi.pamirs.user.api.cache.UserCache;
import pro.shushi.pamirs.user.api.constants.UserConstant;
import pro.shushi.pamirs.user.api.enmu.UserExpEnumerate;
import pro.shushi.pamirs.user.api.enmu.UserLoginTypeEnum;
import pro.shushi.pamirs.user.api.login.IUserLoginChecker;
import pro.shushi.pamirs.user.api.login.UserCookieLogin;
import pro.shushi.pamirs.user.api.login.UserCookieLoginSimple;
import pro.shushi.pamirs.user.api.model.PamirsUser;
import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient;
import pro.shushi.pamirs.user.api.service.UserService;
import pro.shushi.pamirs.user.api.utils.CookieUtil;

import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author shushi
 *
 *  Fully customized login process
 *  Needs to implement the login part login and the interception part fetchUserIdByReq
 *  If the return value of fetchUserIdByReq is null, it will be intercepted
 */
@Slf4j
@Order(0)
@Component
public class DemoUserSSOCookieLogin extends UserCookieLogin<PamirsUser>  {

    // Refresh token
    private static String REFRESH_TOKEN = "refreshToken";
    // System ID
    private static String CLIENT_ID = "client-id";
    // Access token
    private static String AUTHORIZATION = "Authorization";

    private IUserLoginChecker checker;

    @Autowired
    private UserService userService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public String type() {
        return UserLoginTypeEnum.COOKIE.value();
    }

    @Override
    public PamirsUser resolveAndVerification(PamirsUserTransient user) {
        if (checker == null) {
            checker = BeanDefinitionUtils.getBean(IUserLoginChecker.class);
        }
        return checker.check4login(user);
    }

    /**
     * Override the login interception function
     * The main role of this function is to pass third-party permission verification.
     * @return
     */
    // Needs to be modified for version upgrade
    @Override
    public PamirsUserDTO fetchUserIdByReq() {
        String sessionId = PamirsSession.getSessionId();
        PamirsUserDTO pamirsUserDTO = UserCache.get(sessionId);
        if (pamirsUserDTO ==null) {
            // H5-Enterprise WeChat login, other SSO logins. Get the identifier
            String accessToken = (String) PamirsSession.getRequestVariables().getVariables().get("accessToken");
            ApiCommonTransient permissionInfo = AuthenticateUtils.getPermissionInfo(accessToken);
            // *******Login success condition judgment, each SSO modifies it according to the situation********
            if(HttpConstant.SUCCESS.equals(permissionInfo.getCode())) {
                // SSO user to Oinone user
                PamirsUser pamirsUser = setUserInfoToCookiesAndSetUserIdToCache(permissionInfo,accessToken);
                return new PamirsUserDTO().setUserId(pamirsUser.getId()).setPhone(pamirsUser.getPhone())
                .setUserCode(pamirsUser.getCode()).setLogin(pamirsUser.getLogin()).setEmail(pamirsUser.getEmail()).setUserName(pamirsUser.getName());
            } else {
                // The user is not logged in, and the token fails to get the user null (modify according to the actual situation)
                return null;
            }
        } else {
            return fetchUserIdByReq4Pamirs();
        }
    }

    /**
     * Open a user login setCookies function for login and jump verification
     * @param permissionInfo
     * @param accessToken
     * @return
     */
    public PamirsUser setUserInfoToCookiesAndSetUserIdToCache(ApiCommonTransient permissionInfo, String accessToken) {
        PermissionInfoResp ssoResponseTransient = JSON.parseObject(permissionInfo.getData().toString(), PermissionInfoResp.class);
        // *********Example: Association between SSO and user ID in the business system; please process other association conditions according to data conditions*******
        PamirsUser pamirsUser = userService.queryById(ssoResponseTransient.getUserInfo().getId());
        if (pamirsUser == null) {
            // ********What to do if there is user data in SSO but not in Oinone's system************/
            // ********This is just an example. Create a user in the above case. Please handle it according to the actual situation. Please handle it according to the actual situation*****/
            pamirsUser = createOrUpdatePamirsUser(ssoResponseTransient);
        }

        HttpServletResponse httpServletResponse = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        UserCookieLoginSimple userCookieLoginSimple = new UserCookieLoginSimple();
        String sessionId = PamirsSession.getSessionId();
        String cacheKey = userCookieLoginSimple.parseSessionId(sessionId);
        UserCache.putCache(cacheKey, userCookieLoginSimple.coverToUserDTO(pamirsUser));
        PamirsSession.setSessionId(sessionId);
        try {
            CookieUtil.set(httpServletResponse, UserConstant.USER_SESSION_ID, sessionId);
        } catch (Exception e) {
            log.error("SSO Login Cookie Set Err", e);
        }
        // set accessToken to cookies
        /**
        String userCodeCacheKey = SSOConstant.USER_REDIS_CACHE + pamirsUser.getId();
        redisTemplate.opsForValue().set(userCodeCacheKey,accessToken,3600, TimeUnit.SECONDS);
        **/
        return pamirsUser;
    }

    // ********This is just an example. Create a user in the above case. Please handle it according to the actual situation. Please handle it according to the actual situation*****/
    private PamirsUser createOrUpdatePamirsUser(PermissionInfoResp ssoResponseTransient) {
        PamirsUser pamirsUser;
        pamirsUser = new PamirsUser();
        pamirsUser.unsetEmail();
        pamirsUser.unsetPhone() ;
        pamirsUser.setId(ssoResponseTransient.getUserInfo().getId());
        pamirsUser.setUserType(SessionUserTypeEnum.COMPANY_ADMIN.displayName());
        pamirsUser.setSignUpType(UserSignUpType.BACKSTAGE);
        pamirsUser.setName(ssoResponseTransient.getUserInfo().getUsername());
        pamirsUser.setLogin(ssoResponseTransient.getUserInfo().getUsername());
        pamirsUser.setNickname(ssoResponseTransient.getUserInfo().getNickname());
        pamirsUser.setRealname(ssoResponseTransient.getUserInfo().getNickname());
        pamirsUser.setId(ssoResponseTransient.getUserInfo().getId());
        userService.createOrUpdate(pamirsUser);
        return pamirsUser;
    }

    /**
     * Function call after the original user logs in
     * @return
     */
    private PamirsUserDTO fetchUserIdByReq4Pamirs() {
        PamirsUserDTO pamirsUserDTO = super.fetchUserIdByReq();
        if (pamirsUserDTO == null || pamirsUserDTO.getUserId() == null) {
            return pamirsUserDTO;
        }
        PamirsUser user = new PamirsUser().setId(pamirsUserDTO.getUserId()).queryById();
        if (user != null && !Boolean.TRUE.equals(user.getActive())) {
            // Clear the login cookie
            logout();
            log.error("{}The current user is {},{}", UserExpEnumerate.USER_CAN_NOT_ACTIVE_ERROR, pamirsUserDTO.getUserId(), pamirsUserDTO.getLogin());
            throw PamirsException.construct(UserExpEnumerate.USER_CAN_NOT_ACTIVE_ERROR).errThrow();
        }

        return pamirsUserDTO;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

Ⅲ、SSO Docking Example Code Package ​

Example code package download: SSO Docking Demo Example

Pager
Previous pageEnvironment Deployment:Backend No-Code Designer Jar Package Startup Method
Next pageDevelopment Framework:Framework MessageHub(Information Prompt)
On this page