[Open Source] Licensed under the MIT License. Create your own lightweight private notebook, developed based on the SpringBoot ecosystem.
![[Open Source] Licensed under the MIT License. Create your own lightweight private notebook, developed based on the SpringBoot ecosystem.](https://yy123.ink/api/img/1782601750335-eiwf2p.jpg)
1. Project Overview
Easy Notes: Create your own lightweight private notebook.
An API service developed based on the SpringBoot ecosystem, covering technologies such as Spring Security, OAuth2, JWT, and MongoDB.
The client is developed using Vue.js and Ant Design.
2. Open Source License
Licensed under MIT
3. Screenshots
Some screenshots:


4. Feature Overview
Core Function
The notebook and note management features of the project are relatively straightforward, so we won't cover them here. Instead, we'll focus on the OAuth2.0 social login module. All related code is located in the cn.zealon.notes.security package.
OAuth2 Authorization
Refer to the README.md documentation.
Without further ado, let's first look at the interaction process of the OAuth2.0 Authorization Code Grant:

First, the client accesses a social login platform (such as WeChat, GitHub, Weibo, etc.). If the user is not logged in, they will be prompted to log in. Once authenticated, the platform requests the user's authorization. After the user grants permission, the platform returns an authorization code and redirects back to the client. At this point, we use the authorization code and client secret on the server to request an access token. Once we obtain the access token, we use it to retrieve the user's profile information from the social platform. After processing the login, we return a custom Token to the client. Here, we use JWT (JSON Web Token), generating and returning a Token that the client stores locally.

When the client accesses the server API again, it generally includes the Token in the request header. For a monolithic application, the Token can be validated in a filter. For a microservices architecture, validation can be performed at the gateway. If validation succeeds, the request is forwarded to the backend service. During forwarding, the user information extracted from the Token is also passed along, eliminating the need for backend services to parse the Token again to retrieve user information. This entire process is handled centrally by the gateway.
If validation fails, the corresponding response is returned directly to the client without forwarding the request. When the client receives a 401 status code, it prompts the user to log in again.
‼️ One important point worth mentioning: after the client obtains the authorization code, it is technically possible to use the client secret to request an Access Token directly from the frontend. So why do we handle this on the server? Isn't that an unnecessary extra step?
The answer is that this must be handled on the server because exposing the client secret on the frontend is insecure and could allow malicious users to exploit it!
‼️ JWT-generated tokens cannot be modified once issued. If a user changes their password or other account information, the changes will not take effect until the Token expires. Therefore, avoid setting excessively long Token expiration periods. You can extend the session by periodically refreshing the Token.
Login, Registration, and Account Binding in OAuth2 Callback Handling
A single account can be linked to multiple OAuth2 authorizations. For example, the account named Summer can be linked to both QQ and Weibo. Logging in successfully through either OAuth2 provider will access the same account. Here's a brief introduction to OAuth2 callback handling.
Social login services are only responsible for providing authorization. They don't know whether we intend to log in, register, or bind an account. Therefore, whether a successful authorization triggers login, registration, or account binding must be handled by our own business APIs. Understanding this distinction will save you a lot of unnecessary work. Without further ado, let's take a look at the diagram:

The overall process mainly handles three operations: login, registration, and account binding (including some necessary validation logic).
Retrieve Social User Information
We start by using the Access Token to retrieve the OAuth2 user's information. From there, we can implement our own business logic.
Since we integrate multiple social platforms, and each platform returns data in a different format, while our processing logic needs to remain consistent, we use the Strategy Pattern to handle this. This improves extensibility while avoiding lengthy if-else statements.
Business Logic Processing
First, we need to determine whether the user is currently logged in. This can be implemented using security frameworks such as Shiro or Spring Security. In this project, we use Spring Security. The remaining steps involve the specific business logic:
- Login: Directly return a JWT-encrypted Token to the client.
- Automatic Registration: After registering and binding the account, invoke the login logic. The client then redirects directly to the home page, eliminating the need for the user to log in manually.
- Manual Registration: This corresponds to the Prompt Handling branch in the diagram. Since the OAuth2 account has already been linked to another account, the user must provide a custom username. We return the OAuth2 information to the client along with a friendly prompt. When the user submits the registration form, both the OAuth2 information and registration details are included, allowing us to complete the registration and account binding.
- Account Binding: Check whether the OAuth2 username has already been linked to an account. If it hasn't, bind it directly. If it has, notify the client and inform the user that the account is already linked, explaining that they can log in directly using their social account, and so on.
5. Tech Stack
Easy Notes: Create your own lightweight private notebook. The API involves Spring Security, OAuth2, JWT, and MongoDB. The client is developed using Vue.js and Ant Design.
Project Directory
The project adopts a traditional layered architecture:
- src/main/java
- cn.zealon.notes
- common / Common package
- base / Abstract base classes
- config / Project configuration
- exception / Custom exceptions
- result / Response result wrappers
- utils / Utility classes
- controller / Controllers
- domain / Domain objects
- repository / MongoDB storage
- security / Security module
- config / Configuration
- controller / Authentication-related controllers
- domain / Security-related entities
- filter / Custom filters
- jwt / JWT components
- service / API services
- service / Service layer
- vo / View objects
- security / Security handling (Shiro)
- Application.java / Application entry point
- src/main/resources
- application.yml / Application configuration file