jdk 17
This commit is contained in:
2
demo/backend/.gitattributes
vendored
Normal file
2
demo/backend/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/mvnw text eol=lf
|
||||||
|
*.cmd text eol=crlf
|
||||||
33
demo/backend/.gitignore
vendored
Normal file
33
demo/backend/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
295
demo/backend/mvnw
vendored
Normal file
295
demo/backend/mvnw
vendored
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Apache Maven Wrapper startup batch script, version 3.3.4
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||||
|
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
set -euf
|
||||||
|
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||||
|
|
||||||
|
# OS specific support.
|
||||||
|
native_path() { printf %s\\n "$1"; }
|
||||||
|
case "$(uname)" in
|
||||||
|
CYGWIN* | MINGW*)
|
||||||
|
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||||
|
native_path() { cygpath --path --windows "$1"; }
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# set JAVACMD and JAVACCMD
|
||||||
|
set_java_home() {
|
||||||
|
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||||
|
if [ -n "${JAVA_HOME-}" ]; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||||
|
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||||
|
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v java
|
||||||
|
)" || :
|
||||||
|
JAVACCMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v javac
|
||||||
|
)" || :
|
||||||
|
|
||||||
|
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||||
|
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# hash string like Java String::hashCode
|
||||||
|
hash_string() {
|
||||||
|
str="${1:-}" h=0
|
||||||
|
while [ -n "$str" ]; do
|
||||||
|
char="${str%"${str#?}"}"
|
||||||
|
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||||
|
str="${str#?}"
|
||||||
|
done
|
||||||
|
printf %x\\n $h
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose() { :; }
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf %s\\n "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
# MWRAPPER-139:
|
||||||
|
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||||
|
# Needed for removing poorly interpreted newline sequences when running in more
|
||||||
|
# exotic environments such as mingw bash on Windows.
|
||||||
|
printf "%s" "${1}" | tr -d '[:space:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptDir="$(dirname "$0")"
|
||||||
|
scriptName="$(basename "$0")"
|
||||||
|
|
||||||
|
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
while IFS="=" read -r key value; do
|
||||||
|
case "${key-}" in
|
||||||
|
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||||
|
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||||
|
esac
|
||||||
|
done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
|
||||||
|
case "${distributionUrl##*/}" in
|
||||||
|
maven-mvnd-*bin.*)
|
||||||
|
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||||
|
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||||
|
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||||
|
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||||
|
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||||
|
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||||
|
*)
|
||||||
|
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||||
|
distributionPlatform=linux-amd64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||||
|
;;
|
||||||
|
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||||
|
*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||||
|
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||||
|
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||||
|
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||||
|
|
||||||
|
exec_maven() {
|
||||||
|
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||||
|
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -d "$MAVEN_HOME" ]; then
|
||||||
|
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
exec_maven "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${distributionUrl-}" in
|
||||||
|
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||||
|
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||||
|
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||||
|
trap clean HUP INT TERM EXIT
|
||||||
|
else
|
||||||
|
die "cannot create temp dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
verbose "Downloading from: $distributionUrl"
|
||||||
|
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
# select .zip or .tar.gz
|
||||||
|
if ! command -v unzip >/dev/null; then
|
||||||
|
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# verbose opt
|
||||||
|
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||||
|
|
||||||
|
# normalize http auth
|
||||||
|
case "${MVNW_PASSWORD:+has-password}" in
|
||||||
|
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||||
|
verbose "Found wget ... using wget"
|
||||||
|
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||||
|
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||||
|
verbose "Found curl ... using curl"
|
||||||
|
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||||
|
elif set_java_home; then
|
||||||
|
verbose "Falling back to use Java to download"
|
||||||
|
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||||
|
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
cat >"$javaSource" <<-END
|
||||||
|
public class Downloader extends java.net.Authenticator
|
||||||
|
{
|
||||||
|
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||||
|
{
|
||||||
|
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||||
|
}
|
||||||
|
public static void main( String[] args ) throws Exception
|
||||||
|
{
|
||||||
|
setDefault( new Downloader() );
|
||||||
|
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END
|
||||||
|
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||||
|
verbose " - Compiling Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||||
|
verbose " - Running Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
if [ -n "${distributionSha256Sum-}" ]; then
|
||||||
|
distributionSha256Result=false
|
||||||
|
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||||
|
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||||
|
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
elif command -v sha256sum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
elif command -v shasum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||||
|
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $distributionSha256Result = false ]; then
|
||||||
|
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||||
|
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
if command -v unzip >/dev/null; then
|
||||||
|
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||||
|
else
|
||||||
|
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find the actual extracted directory name (handles snapshots where filename != directory name)
|
||||||
|
actualDistributionDir=""
|
||||||
|
|
||||||
|
# First try the expected directory name (for regular distributions)
|
||||||
|
if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
|
||||||
|
if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
|
||||||
|
actualDistributionDir="$distributionUrlNameMain"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If not found, search for any directory with the Maven executable (for snapshots)
|
||||||
|
if [ -z "$actualDistributionDir" ]; then
|
||||||
|
# enable globbing to iterate over items
|
||||||
|
set +f
|
||||||
|
for dir in "$TMP_DOWNLOAD_DIR"/*; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
if [ -f "$dir/bin/$MVN_CMD" ]; then
|
||||||
|
actualDistributionDir="$(basename "$dir")"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
set -f
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$actualDistributionDir" ]; then
|
||||||
|
verbose "Contents of $TMP_DOWNLOAD_DIR:"
|
||||||
|
verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
|
||||||
|
die "Could not find Maven distribution directory in extracted archive"
|
||||||
|
fi
|
||||||
|
|
||||||
|
verbose "Found extracted Maven distribution directory: $actualDistributionDir"
|
||||||
|
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
|
||||||
|
mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||||
|
|
||||||
|
clean || :
|
||||||
|
exec_maven "$@"
|
||||||
189
demo/backend/mvnw.cmd
vendored
Normal file
189
demo/backend/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
<# : batch portion
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Apache Maven Wrapper startup batch script, version 3.3.4
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||||
|
@SET __MVNW_CMD__=
|
||||||
|
@SET __MVNW_ERROR__=
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||||
|
@SET PSModulePath=
|
||||||
|
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||||
|
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||||
|
)
|
||||||
|
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=
|
||||||
|
@SET __MVNW_ARG0_NAME__=
|
||||||
|
@SET MVNW_USERNAME=
|
||||||
|
@SET MVNW_PASSWORD=
|
||||||
|
@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*)
|
||||||
|
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||||
|
@GOTO :EOF
|
||||||
|
: end batch / begin powershell #>
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
if ($env:MVNW_VERBOSE -eq "true") {
|
||||||
|
$VerbosePreference = "Continue"
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||||
|
if (!$distributionUrl) {
|
||||||
|
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||||
|
"maven-mvnd-*" {
|
||||||
|
$USE_MVND = $true
|
||||||
|
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||||
|
$MVN_CMD = "mvnd.cmd"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
$USE_MVND = $false
|
||||||
|
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
if ($env:MVNW_REPOURL) {
|
||||||
|
$MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||||
|
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')"
|
||||||
|
}
|
||||||
|
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||||
|
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||||
|
|
||||||
|
$MAVEN_M2_PATH = "$HOME/.m2"
|
||||||
|
if ($env:MAVEN_USER_HOME) {
|
||||||
|
$MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
|
||||||
|
New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
$MAVEN_WRAPPER_DISTS = $null
|
||||||
|
if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
|
||||||
|
$MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
|
||||||
|
} else {
|
||||||
|
$MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
|
||||||
|
}
|
||||||
|
|
||||||
|
$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
|
||||||
|
$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||||
|
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||||
|
|
||||||
|
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||||
|
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
exit $?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||||
|
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||||
|
}
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||||
|
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||||
|
trap {
|
||||||
|
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
Write-Verbose "Downloading from: $distributionUrl"
|
||||||
|
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||||
|
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||||
|
}
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||||
|
if ($distributionSha256Sum) {
|
||||||
|
if ($USE_MVND) {
|
||||||
|
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||||
|
}
|
||||||
|
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||||
|
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||||
|
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||||
|
|
||||||
|
# Find the actual extracted directory name (handles snapshots where filename != directory name)
|
||||||
|
$actualDistributionDir = ""
|
||||||
|
|
||||||
|
# First try the expected directory name (for regular distributions)
|
||||||
|
$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
|
||||||
|
$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
|
||||||
|
if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
|
||||||
|
$actualDistributionDir = $distributionUrlNameMain
|
||||||
|
}
|
||||||
|
|
||||||
|
# If not found, search for any directory with the Maven executable (for snapshots)
|
||||||
|
if (!$actualDistributionDir) {
|
||||||
|
Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
|
||||||
|
$testPath = Join-Path $_.FullName "bin/$MVN_CMD"
|
||||||
|
if (Test-Path -Path $testPath -PathType Leaf) {
|
||||||
|
$actualDistributionDir = $_.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$actualDistributionDir) {
|
||||||
|
Write-Error "Could not find Maven distribution directory in extracted archive"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
|
||||||
|
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||||
|
try {
|
||||||
|
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||||
|
} catch {
|
||||||
|
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||||
|
Write-Error "fail to move MAVEN_HOME"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
63
demo/backend/pom.xml
Normal file
63
demo/backend/pom.xml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.5.10</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>org.lingniu</groupId>
|
||||||
|
<artifactId>demo</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>demo</name>
|
||||||
|
<description>demo</description>
|
||||||
|
<url/>
|
||||||
|
<licenses>
|
||||||
|
<license/>
|
||||||
|
</licenses>
|
||||||
|
<developers>
|
||||||
|
<developer/>
|
||||||
|
</developers>
|
||||||
|
<scm>
|
||||||
|
<connection/>
|
||||||
|
<developerConnection/>
|
||||||
|
<tag/>
|
||||||
|
<url/>
|
||||||
|
</scm>
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.lingniu</groupId>
|
||||||
|
<artifactId>oauth2-login-sdk</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example.demo;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication(scanBasePackages = {"org.lingniu.**"})
|
||||||
|
public class DemoApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(DemoApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
demo/backend/src/main/java/com/example/demo/test.http
Normal file
41
demo/backend/src/main/java/com/example/demo/test.http
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# @no-redirect
|
||||||
|
GET localhost:10001/oauth2/authorization/demo
|
||||||
|
|
||||||
|
###
|
||||||
|
POST http://localhost:8000/oauth2/authorize
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
Accept: application/json
|
||||||
|
Idp: 387cec08371f4ebfb61074d41a94046e
|
||||||
|
Cookie: idp_refresh_token=7bb21a0dcac94aec99f08ae6a2d6db30
|
||||||
|
|
||||||
|
response_type=code&client_id=b55c88c20db94790a60a5075&scope=openid%20profile%20perms&state=MK1s_JKXsVowOsaGIGK3UK00yVgjUM-lgV-T7tOZdIQ%3D&redirect_uri=http://localhost:9506/oauth2/callback&nonce=rXdsOr0tczTckUSP_RKZ5ABmP575Z4JrTLOxCQ1nt3U
|
||||||
|
|
||||||
|
|
||||||
|
####
|
||||||
|
GET http://localhost:10001/login/oauth2/code/demo?code=ua3zRRX2YMHsGmYaY4CGEvtklZbCzNtT5sOjguXzhY68zoKqnA83NlQXtG1dN-X_mv4Sn5MaYERkymxk9EWJzpHA_RB523keRb25jmIt5LgUjWJtwD4gJmQJulPOXFO1&state=MK1s_JKXsVowOsaGIGK3UK00yVgjUM-lgV-T7tOZdIQ%3D
|
||||||
|
|
||||||
|
###
|
||||||
|
GET http://localhost:10001/idp/routes
|
||||||
|
#Authorization: 85a9f4d6fef34763b4437830ec331570
|
||||||
|
Authorization: Bearer eyJraWQiOiJpZHAiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6ImI1NWM4OGMyMGRiOTQ3OTBhNjBhNTA3NSIsIm5iZiI6MTc3MDM5MjMwMiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsInBlcm1zIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMCIsImV4cCI6MTc3MDQzNTUwMiwiaWF0IjoxNzcwMzkyMzAyLCJqdGkiOiIxMmRjZjZmOS0zMjNhLTRhMmUtYjI4Ni1lNDcyOTFhNjc4YTYifQ.MC2khfn7Q2PeU5NB9BCazj-4oWsS_9VIoRLvVZfRiM4RKyAw6VkBv0bNWNuIcUAzZ7GpfIsGMufjsDiVgj7tBK_MWweasWz7DRDc_QCkFt8RZxK2LjxZAilFmXZOaydUNnlGgBmI6S-xAD5N5ltx8OTEdWHuD7tm7S8ppXlvTCk4QSeNd3UYXyXPkR408HOk5ZWTH4PudGVJN5q5gDUAbM9FyN7NejGuJQ4gmHuur7oDhMEqmBQjiv6OnJZko6GszOcN0-nkRJX-KzXV45uIkEF9BaUhJvC6EhotqioVXLuLznX3yB9iuFGqekpS3uHOYwzZF0CHR6xTHg29hvLOxw
|
||||||
|
#Cookie: app_refresh_token=ce08d9a6b3064311ac163a7806b811ef
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
GET http://localhost:8000/account/getRouters
|
||||||
|
#Authorization: 85a9f4d6fef34763b4437830ec331570
|
||||||
|
Authorization: Bearer eyJraWQiOiJpZHAiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6ImI1NWM4OGMyMGRiOTQ3OTBhNjBhNTA3NSIsIm5iZiI6MTc3MDM5MjMwMiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsInBlcm1zIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMCIsImV4cCI6MTc3MDQzNTUwMiwiaWF0IjoxNzcwMzkyMzAyLCJqdGkiOiIxMmRjZjZmOS0zMjNhLTRhMmUtYjI4Ni1lNDcyOTFhNjc4YTYifQ.MC2khfn7Q2PeU5NB9BCazj-4oWsS_9VIoRLvVZfRiM4RKyAw6VkBv0bNWNuIcUAzZ7GpfIsGMufjsDiVgj7tBK_MWweasWz7DRDc_QCkFt8RZxK2LjxZAilFmXZOaydUNnlGgBmI6S-xAD5N5ltx8OTEdWHuD7tm7S8ppXlvTCk4QSeNd3UYXyXPkR408HOk5ZWTH4PudGVJN5q5gDUAbM9FyN7NejGuJQ4gmHuur7oDhMEqmBQjiv6OnJZko6GszOcN0-nkRJX-KzXV45uIkEF9BaUhJvC6EhotqioVXLuLznX3yB9iuFGqekpS3uHOYwzZF0CHR6xTHg29hvLOxw
|
||||||
|
#Cookie: app_refresh_token=ce08d9a6b3064311ac163a7806b811ef
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
####
|
||||||
|
GET http://localhost:10001/idp/routes
|
||||||
|
#Authorization: 85a9f4d6fef34763b4437830ec331570
|
||||||
|
Authorization: 41deb286d03b42139bc3559cbbcc9995
|
||||||
|
#Cookie: app_refresh_token=ce08d9a6b3064311ac163a7806b811ef
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
|
POST http://localhost:10001/logout
|
||||||
|
Cookie: app_refresh_token=02237ce2c5d14e8088be3d462b69df99
|
||||||
|
|
||||||
70
demo/backend/src/main/resources/application.yml
Normal file
70
demo/backend/src/main/resources/application.yml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: demo
|
||||||
|
# redis \u914D\u7F6E
|
||||||
|
security:
|
||||||
|
oauth2:
|
||||||
|
resourceserver:
|
||||||
|
jwt:
|
||||||
|
jwk-set-uri: http://localhost:8000/oauth2/jwks
|
||||||
|
client:
|
||||||
|
registration:
|
||||||
|
demo:
|
||||||
|
client-id: b55c88c20db94790a60a5075
|
||||||
|
client-secret: UqVAS8UiehSFJSR8_CygnYGR5M79LuGuGiDwATtcGqg
|
||||||
|
client-name: DEMO
|
||||||
|
authorization-grant-type: authorization_code
|
||||||
|
redirect-uri: http://localhost:9506/oauth2/callback
|
||||||
|
scope:
|
||||||
|
- openid
|
||||||
|
- profile
|
||||||
|
# 返回权限
|
||||||
|
- perms
|
||||||
|
provider: idp
|
||||||
|
|
||||||
|
provider:
|
||||||
|
idp:
|
||||||
|
# issuer-uri: http://localhost:8000
|
||||||
|
authorization-uri: http://localhost/sso
|
||||||
|
token-uri: http://localhost:8000/oauth2/token
|
||||||
|
user-info-uri: http://localhost:8000/userinfo
|
||||||
|
jwk-set-uri: http://localhost:8000/oauth2/jwks
|
||||||
|
user-name-attribute: sub
|
||||||
|
data:
|
||||||
|
redis:
|
||||||
|
# \u5730\u5740
|
||||||
|
host: localhost
|
||||||
|
# \u7AEF\u53E3\uFF0C\u9ED8\u8BA4\u4E3A6379
|
||||||
|
port: 6379
|
||||||
|
# \u6570\u636E\u5E93\u7D22\u5F15
|
||||||
|
database: 0
|
||||||
|
# \u5BC6\u7801
|
||||||
|
password:
|
||||||
|
# \u8FDE\u63A5\u8D85\u65F6\u65F6\u95F4
|
||||||
|
timeout: 10s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5
|
||||||
|
min-idle: 0
|
||||||
|
# \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5
|
||||||
|
max-idle: 8
|
||||||
|
# \u8FDE\u63A5\u6C60\u7684\u6700\u5927\u6570\u636E\u5E93\u8FDE\u63A5\u6570
|
||||||
|
max-active: 8
|
||||||
|
# #\u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09
|
||||||
|
max-wait: -1ms
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
root: info
|
||||||
|
org.springframework.web: debug
|
||||||
|
org.springframework.security: debug
|
||||||
|
org.springframework.security.oauth2: debug
|
||||||
|
|
||||||
|
|
||||||
|
server:
|
||||||
|
port: 10001
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example.demo;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class DemoApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
24
demo/frontend/.gitignore
vendored
Normal file
24
demo/frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
5
demo/frontend/README.md
Normal file
5
demo/frontend/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Vue 3 + TypeScript + Vite
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||||
|
|
||||||
|
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
||||||
13
demo/frontend/index.html
Normal file
13
demo/frontend/index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>demo-sdk</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
24
demo/frontend/package.json
Normal file
24
demo/frontend/package.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "demo-sdk",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vue-tsc -b && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"oauth2-login-sdk": "link:C:/Users/admin/AppData/Local/pnpm/global/5/node_modules/oauth2-login-sdk",
|
||||||
|
"vue": "^3.5.24",
|
||||||
|
"vue-router": "^4.3.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^24.10.1",
|
||||||
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
|
"@vue/tsconfig": "^0.8.1",
|
||||||
|
"typescript": "~5.9.3",
|
||||||
|
"vite": "^7.2.4",
|
||||||
|
"vue-tsc": "^3.1.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
976
demo/frontend/pnpm-lock.yaml
generated
Normal file
976
demo/frontend/pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,976 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
overrides:
|
||||||
|
oauth2-login-sdk: link:C:/Users/admin/AppData/Local/pnpm/global/5/node_modules/oauth2-login-sdk
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
dependencies:
|
||||||
|
oauth2-login-sdk:
|
||||||
|
specifier: link:C:/Users/admin/AppData/Local/pnpm/global/5/node_modules/oauth2-login-sdk
|
||||||
|
version: link:C:/Users/admin/AppData/Local/pnpm/global/5/node_modules/oauth2-login-sdk
|
||||||
|
vue:
|
||||||
|
specifier: ^3.5.24
|
||||||
|
version: 3.5.27(typescript@5.9.3)
|
||||||
|
vue-router:
|
||||||
|
specifier: ^4.3.0
|
||||||
|
version: 4.6.4(vue@3.5.27(typescript@5.9.3))
|
||||||
|
devDependencies:
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^24.10.1
|
||||||
|
version: 24.10.10
|
||||||
|
'@vitejs/plugin-vue':
|
||||||
|
specifier: ^6.0.1
|
||||||
|
version: 6.0.4(vite@7.3.1(@types/node@24.10.10))(vue@3.5.27(typescript@5.9.3))
|
||||||
|
'@vue/tsconfig':
|
||||||
|
specifier: ^0.8.1
|
||||||
|
version: 0.8.1(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))
|
||||||
|
typescript:
|
||||||
|
specifier: ~5.9.3
|
||||||
|
version: 5.9.3
|
||||||
|
vite:
|
||||||
|
specifier: ^7.2.4
|
||||||
|
version: 7.3.1(@types/node@24.10.10)
|
||||||
|
vue-tsc:
|
||||||
|
specifier: ^3.1.4
|
||||||
|
version: 3.2.4(typescript@5.9.3)
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@babel/helper-string-parser@7.27.1':
|
||||||
|
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.28.5':
|
||||||
|
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/parser@7.29.0':
|
||||||
|
resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@babel/types@7.29.0':
|
||||||
|
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [aix]
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.27.2':
|
||||||
|
resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.27.2':
|
||||||
|
resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.27.2':
|
||||||
|
resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.27.2':
|
||||||
|
resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [mips64el]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.27.2':
|
||||||
|
resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [sunos]
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.27.2':
|
||||||
|
resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.27.2':
|
||||||
|
resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5':
|
||||||
|
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||||
|
|
||||||
|
'@rolldown/pluginutils@1.0.0-rc.2':
|
||||||
|
resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==}
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm-eabi@4.57.1':
|
||||||
|
resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm64@4.57.1':
|
||||||
|
resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-arm64@4.57.1':
|
||||||
|
resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-x64@4.57.1':
|
||||||
|
resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-arm64@4.57.1':
|
||||||
|
resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-x64@4.57.1':
|
||||||
|
resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf@4.57.1':
|
||||||
|
resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf@4.57.1':
|
||||||
|
resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-gnu@4.57.1':
|
||||||
|
resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-musl@4.57.1':
|
||||||
|
resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-gnu@4.57.1':
|
||||||
|
resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-musl@4.57.1':
|
||||||
|
resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu@4.57.1':
|
||||||
|
resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-musl@4.57.1':
|
||||||
|
resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu@4.57.1':
|
||||||
|
resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-musl@4.57.1':
|
||||||
|
resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-s390x-gnu@4.57.1':
|
||||||
|
resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-gnu@4.57.1':
|
||||||
|
resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-musl@4.57.1':
|
||||||
|
resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-openbsd-x64@4.57.1':
|
||||||
|
resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-openharmony-arm64@4.57.1':
|
||||||
|
resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-arm64-msvc@4.57.1':
|
||||||
|
resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-ia32-msvc@4.57.1':
|
||||||
|
resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-gnu@4.57.1':
|
||||||
|
resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-msvc@4.57.1':
|
||||||
|
resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@types/estree@1.0.8':
|
||||||
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
|
'@types/node@24.10.10':
|
||||||
|
resolution: {integrity: sha512-+0/4J266CBGPUq/ELg7QUHhN25WYjE0wYTPSQJn1xeu8DOlIOPxXxrNGiLmfAWl7HMMgWFWXpt9IDjMWrF5Iow==}
|
||||||
|
|
||||||
|
'@vitejs/plugin-vue@6.0.4':
|
||||||
|
resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
peerDependencies:
|
||||||
|
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
|
||||||
|
vue: ^3.2.25
|
||||||
|
|
||||||
|
'@volar/language-core@2.4.27':
|
||||||
|
resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==}
|
||||||
|
|
||||||
|
'@volar/source-map@2.4.27':
|
||||||
|
resolution: {integrity: sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==}
|
||||||
|
|
||||||
|
'@volar/typescript@2.4.27':
|
||||||
|
resolution: {integrity: sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg==}
|
||||||
|
|
||||||
|
'@vue/compiler-core@3.5.27':
|
||||||
|
resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==}
|
||||||
|
|
||||||
|
'@vue/compiler-dom@3.5.27':
|
||||||
|
resolution: {integrity: sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==}
|
||||||
|
|
||||||
|
'@vue/compiler-sfc@3.5.27':
|
||||||
|
resolution: {integrity: sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==}
|
||||||
|
|
||||||
|
'@vue/compiler-ssr@3.5.27':
|
||||||
|
resolution: {integrity: sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==}
|
||||||
|
|
||||||
|
'@vue/devtools-api@6.6.4':
|
||||||
|
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
|
||||||
|
|
||||||
|
'@vue/language-core@3.2.4':
|
||||||
|
resolution: {integrity: sha512-bqBGuSG4KZM45KKTXzGtoCl9cWju5jsaBKaJJe3h5hRAAWpZUuj5G+L+eI01sPIkm4H6setKRlw7E85wLdDNew==}
|
||||||
|
|
||||||
|
'@vue/reactivity@3.5.27':
|
||||||
|
resolution: {integrity: sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==}
|
||||||
|
|
||||||
|
'@vue/runtime-core@3.5.27':
|
||||||
|
resolution: {integrity: sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==}
|
||||||
|
|
||||||
|
'@vue/runtime-dom@3.5.27':
|
||||||
|
resolution: {integrity: sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==}
|
||||||
|
|
||||||
|
'@vue/server-renderer@3.5.27':
|
||||||
|
resolution: {integrity: sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: 3.5.27
|
||||||
|
|
||||||
|
'@vue/shared@3.5.27':
|
||||||
|
resolution: {integrity: sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==}
|
||||||
|
|
||||||
|
'@vue/tsconfig@0.8.1':
|
||||||
|
resolution: {integrity: sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g==}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: 5.x
|
||||||
|
vue: ^3.4.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
vue:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
alien-signals@3.1.2:
|
||||||
|
resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==}
|
||||||
|
|
||||||
|
csstype@3.2.3:
|
||||||
|
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||||
|
|
||||||
|
entities@7.0.1:
|
||||||
|
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
|
esbuild@0.27.2:
|
||||||
|
resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
estree-walker@2.0.2:
|
||||||
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
|
|
||||||
|
fdir@6.5.0:
|
||||||
|
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
picomatch: ^3 || ^4
|
||||||
|
peerDependenciesMeta:
|
||||||
|
picomatch:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
magic-string@0.30.21:
|
||||||
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
|
muggle-string@0.4.1:
|
||||||
|
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
|
||||||
|
|
||||||
|
nanoid@3.3.11:
|
||||||
|
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||||
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
path-browserify@1.0.1:
|
||||||
|
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||||
|
|
||||||
|
picocolors@1.1.1:
|
||||||
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
|
picomatch@4.0.3:
|
||||||
|
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
postcss@8.5.6:
|
||||||
|
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
rollup@4.57.1:
|
||||||
|
resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==}
|
||||||
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
source-map-js@1.2.1:
|
||||||
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
tinyglobby@0.2.15:
|
||||||
|
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
|
typescript@5.9.3:
|
||||||
|
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||||
|
engines: {node: '>=14.17'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
undici-types@7.16.0:
|
||||||
|
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||||
|
|
||||||
|
vite@7.3.1:
|
||||||
|
resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@types/node': ^20.19.0 || >=22.12.0
|
||||||
|
jiti: '>=1.21.0'
|
||||||
|
less: ^4.0.0
|
||||||
|
lightningcss: ^1.21.0
|
||||||
|
sass: ^1.70.0
|
||||||
|
sass-embedded: ^1.70.0
|
||||||
|
stylus: '>=0.54.8'
|
||||||
|
sugarss: ^5.0.0
|
||||||
|
terser: ^5.16.0
|
||||||
|
tsx: ^4.8.1
|
||||||
|
yaml: ^2.4.2
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
jiti:
|
||||||
|
optional: true
|
||||||
|
less:
|
||||||
|
optional: true
|
||||||
|
lightningcss:
|
||||||
|
optional: true
|
||||||
|
sass:
|
||||||
|
optional: true
|
||||||
|
sass-embedded:
|
||||||
|
optional: true
|
||||||
|
stylus:
|
||||||
|
optional: true
|
||||||
|
sugarss:
|
||||||
|
optional: true
|
||||||
|
terser:
|
||||||
|
optional: true
|
||||||
|
tsx:
|
||||||
|
optional: true
|
||||||
|
yaml:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
vscode-uri@3.1.0:
|
||||||
|
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
|
||||||
|
|
||||||
|
vue-router@4.6.4:
|
||||||
|
resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.0
|
||||||
|
|
||||||
|
vue-tsc@3.2.4:
|
||||||
|
resolution: {integrity: sha512-xj3YCvSLNDKt1iF9OcImWHhmYcihVu9p4b9s4PGR/qp6yhW+tZJaypGxHScRyOrdnHvaOeF+YkZOdKwbgGvp5g==}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '>=5.0.0'
|
||||||
|
|
||||||
|
vue@3.5.27:
|
||||||
|
resolution: {integrity: sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@babel/helper-string-parser@7.27.1': {}
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.28.5': {}
|
||||||
|
|
||||||
|
'@babel/parser@7.29.0':
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.29.0
|
||||||
|
|
||||||
|
'@babel/types@7.29.0':
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-string-parser': 7.27.1
|
||||||
|
'@babel/helper-validator-identifier': 7.28.5
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.27.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
|
|
||||||
|
'@rolldown/pluginutils@1.0.0-rc.2': {}
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm-eabi@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm64@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-arm64@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-x64@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-arm64@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-x64@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-gnu@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-musl@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-gnu@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-musl@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-musl@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-musl@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-s390x-gnu@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-gnu@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-musl@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-openbsd-x64@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-openharmony-arm64@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-arm64-msvc@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-ia32-msvc@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-gnu@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-msvc@4.57.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
|
'@types/node@24.10.10':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 7.16.0
|
||||||
|
|
||||||
|
'@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.10.10))(vue@3.5.27(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
'@rolldown/pluginutils': 1.0.0-rc.2
|
||||||
|
vite: 7.3.1(@types/node@24.10.10)
|
||||||
|
vue: 3.5.27(typescript@5.9.3)
|
||||||
|
|
||||||
|
'@volar/language-core@2.4.27':
|
||||||
|
dependencies:
|
||||||
|
'@volar/source-map': 2.4.27
|
||||||
|
|
||||||
|
'@volar/source-map@2.4.27': {}
|
||||||
|
|
||||||
|
'@volar/typescript@2.4.27':
|
||||||
|
dependencies:
|
||||||
|
'@volar/language-core': 2.4.27
|
||||||
|
path-browserify: 1.0.1
|
||||||
|
vscode-uri: 3.1.0
|
||||||
|
|
||||||
|
'@vue/compiler-core@3.5.27':
|
||||||
|
dependencies:
|
||||||
|
'@babel/parser': 7.29.0
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
entities: 7.0.1
|
||||||
|
estree-walker: 2.0.2
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
'@vue/compiler-dom@3.5.27':
|
||||||
|
dependencies:
|
||||||
|
'@vue/compiler-core': 3.5.27
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
|
||||||
|
'@vue/compiler-sfc@3.5.27':
|
||||||
|
dependencies:
|
||||||
|
'@babel/parser': 7.29.0
|
||||||
|
'@vue/compiler-core': 3.5.27
|
||||||
|
'@vue/compiler-dom': 3.5.27
|
||||||
|
'@vue/compiler-ssr': 3.5.27
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
estree-walker: 2.0.2
|
||||||
|
magic-string: 0.30.21
|
||||||
|
postcss: 8.5.6
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
'@vue/compiler-ssr@3.5.27':
|
||||||
|
dependencies:
|
||||||
|
'@vue/compiler-dom': 3.5.27
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
|
||||||
|
'@vue/devtools-api@6.6.4': {}
|
||||||
|
|
||||||
|
'@vue/language-core@3.2.4':
|
||||||
|
dependencies:
|
||||||
|
'@volar/language-core': 2.4.27
|
||||||
|
'@vue/compiler-dom': 3.5.27
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
alien-signals: 3.1.2
|
||||||
|
muggle-string: 0.4.1
|
||||||
|
path-browserify: 1.0.1
|
||||||
|
picomatch: 4.0.3
|
||||||
|
|
||||||
|
'@vue/reactivity@3.5.27':
|
||||||
|
dependencies:
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
|
||||||
|
'@vue/runtime-core@3.5.27':
|
||||||
|
dependencies:
|
||||||
|
'@vue/reactivity': 3.5.27
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
|
||||||
|
'@vue/runtime-dom@3.5.27':
|
||||||
|
dependencies:
|
||||||
|
'@vue/reactivity': 3.5.27
|
||||||
|
'@vue/runtime-core': 3.5.27
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
csstype: 3.2.3
|
||||||
|
|
||||||
|
'@vue/server-renderer@3.5.27(vue@3.5.27(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
'@vue/compiler-ssr': 3.5.27
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
vue: 3.5.27(typescript@5.9.3)
|
||||||
|
|
||||||
|
'@vue/shared@3.5.27': {}
|
||||||
|
|
||||||
|
'@vue/tsconfig@0.8.1(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))':
|
||||||
|
optionalDependencies:
|
||||||
|
typescript: 5.9.3
|
||||||
|
vue: 3.5.27(typescript@5.9.3)
|
||||||
|
|
||||||
|
alien-signals@3.1.2: {}
|
||||||
|
|
||||||
|
csstype@3.2.3: {}
|
||||||
|
|
||||||
|
entities@7.0.1: {}
|
||||||
|
|
||||||
|
esbuild@0.27.2:
|
||||||
|
optionalDependencies:
|
||||||
|
'@esbuild/aix-ppc64': 0.27.2
|
||||||
|
'@esbuild/android-arm': 0.27.2
|
||||||
|
'@esbuild/android-arm64': 0.27.2
|
||||||
|
'@esbuild/android-x64': 0.27.2
|
||||||
|
'@esbuild/darwin-arm64': 0.27.2
|
||||||
|
'@esbuild/darwin-x64': 0.27.2
|
||||||
|
'@esbuild/freebsd-arm64': 0.27.2
|
||||||
|
'@esbuild/freebsd-x64': 0.27.2
|
||||||
|
'@esbuild/linux-arm': 0.27.2
|
||||||
|
'@esbuild/linux-arm64': 0.27.2
|
||||||
|
'@esbuild/linux-ia32': 0.27.2
|
||||||
|
'@esbuild/linux-loong64': 0.27.2
|
||||||
|
'@esbuild/linux-mips64el': 0.27.2
|
||||||
|
'@esbuild/linux-ppc64': 0.27.2
|
||||||
|
'@esbuild/linux-riscv64': 0.27.2
|
||||||
|
'@esbuild/linux-s390x': 0.27.2
|
||||||
|
'@esbuild/linux-x64': 0.27.2
|
||||||
|
'@esbuild/netbsd-arm64': 0.27.2
|
||||||
|
'@esbuild/netbsd-x64': 0.27.2
|
||||||
|
'@esbuild/openbsd-arm64': 0.27.2
|
||||||
|
'@esbuild/openbsd-x64': 0.27.2
|
||||||
|
'@esbuild/openharmony-arm64': 0.27.2
|
||||||
|
'@esbuild/sunos-x64': 0.27.2
|
||||||
|
'@esbuild/win32-arm64': 0.27.2
|
||||||
|
'@esbuild/win32-ia32': 0.27.2
|
||||||
|
'@esbuild/win32-x64': 0.27.2
|
||||||
|
|
||||||
|
estree-walker@2.0.2: {}
|
||||||
|
|
||||||
|
fdir@6.5.0(picomatch@4.0.3):
|
||||||
|
optionalDependencies:
|
||||||
|
picomatch: 4.0.3
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
magic-string@0.30.21:
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
muggle-string@0.4.1: {}
|
||||||
|
|
||||||
|
nanoid@3.3.11: {}
|
||||||
|
|
||||||
|
path-browserify@1.0.1: {}
|
||||||
|
|
||||||
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
|
picomatch@4.0.3: {}
|
||||||
|
|
||||||
|
postcss@8.5.6:
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.11
|
||||||
|
picocolors: 1.1.1
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
rollup@4.57.1:
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
optionalDependencies:
|
||||||
|
'@rollup/rollup-android-arm-eabi': 4.57.1
|
||||||
|
'@rollup/rollup-android-arm64': 4.57.1
|
||||||
|
'@rollup/rollup-darwin-arm64': 4.57.1
|
||||||
|
'@rollup/rollup-darwin-x64': 4.57.1
|
||||||
|
'@rollup/rollup-freebsd-arm64': 4.57.1
|
||||||
|
'@rollup/rollup-freebsd-x64': 4.57.1
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf': 4.57.1
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf': 4.57.1
|
||||||
|
'@rollup/rollup-linux-arm64-gnu': 4.57.1
|
||||||
|
'@rollup/rollup-linux-arm64-musl': 4.57.1
|
||||||
|
'@rollup/rollup-linux-loong64-gnu': 4.57.1
|
||||||
|
'@rollup/rollup-linux-loong64-musl': 4.57.1
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu': 4.57.1
|
||||||
|
'@rollup/rollup-linux-ppc64-musl': 4.57.1
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu': 4.57.1
|
||||||
|
'@rollup/rollup-linux-riscv64-musl': 4.57.1
|
||||||
|
'@rollup/rollup-linux-s390x-gnu': 4.57.1
|
||||||
|
'@rollup/rollup-linux-x64-gnu': 4.57.1
|
||||||
|
'@rollup/rollup-linux-x64-musl': 4.57.1
|
||||||
|
'@rollup/rollup-openbsd-x64': 4.57.1
|
||||||
|
'@rollup/rollup-openharmony-arm64': 4.57.1
|
||||||
|
'@rollup/rollup-win32-arm64-msvc': 4.57.1
|
||||||
|
'@rollup/rollup-win32-ia32-msvc': 4.57.1
|
||||||
|
'@rollup/rollup-win32-x64-gnu': 4.57.1
|
||||||
|
'@rollup/rollup-win32-x64-msvc': 4.57.1
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
tinyglobby@0.2.15:
|
||||||
|
dependencies:
|
||||||
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
|
picomatch: 4.0.3
|
||||||
|
|
||||||
|
typescript@5.9.3: {}
|
||||||
|
|
||||||
|
undici-types@7.16.0: {}
|
||||||
|
|
||||||
|
vite@7.3.1(@types/node@24.10.10):
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.27.2
|
||||||
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
|
picomatch: 4.0.3
|
||||||
|
postcss: 8.5.6
|
||||||
|
rollup: 4.57.1
|
||||||
|
tinyglobby: 0.2.15
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/node': 24.10.10
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
vscode-uri@3.1.0: {}
|
||||||
|
|
||||||
|
vue-router@4.6.4(vue@3.5.27(typescript@5.9.3)):
|
||||||
|
dependencies:
|
||||||
|
'@vue/devtools-api': 6.6.4
|
||||||
|
vue: 3.5.27(typescript@5.9.3)
|
||||||
|
|
||||||
|
vue-tsc@3.2.4(typescript@5.9.3):
|
||||||
|
dependencies:
|
||||||
|
'@volar/typescript': 2.4.27
|
||||||
|
'@vue/language-core': 3.2.4
|
||||||
|
typescript: 5.9.3
|
||||||
|
|
||||||
|
vue@3.5.27(typescript@5.9.3):
|
||||||
|
dependencies:
|
||||||
|
'@vue/compiler-dom': 3.5.27
|
||||||
|
'@vue/compiler-sfc': 3.5.27
|
||||||
|
'@vue/runtime-dom': 3.5.27
|
||||||
|
'@vue/server-renderer': 3.5.27(vue@3.5.27(typescript@5.9.3))
|
||||||
|
'@vue/shared': 3.5.27
|
||||||
|
optionalDependencies:
|
||||||
|
typescript: 5.9.3
|
||||||
2
demo/frontend/pnpm-workspace.yaml
Normal file
2
demo/frontend/pnpm-workspace.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
overrides:
|
||||||
|
oauth2-login-sdk: link:C:/Users/admin/AppData/Local/pnpm/global/5/node_modules/oauth2-login-sdk
|
||||||
1
demo/frontend/public/vite.svg
Normal file
1
demo/frontend/public/vite.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
9
demo/frontend/src/App.vue
Normal file
9
demo/frontend/src/App.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
1
demo/frontend/src/assets/vue.svg
Normal file
1
demo/frontend/src/assets/vue.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 496 B |
37
demo/frontend/src/components/Home.vue
Normal file
37
demo/frontend/src/components/Home.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
hello {{ userInfo?.username }} is login
|
||||||
|
<div v-if="loading">Loading menus...</div>
|
||||||
|
<div v-else>
|
||||||
|
menus:
|
||||||
|
{{ JSON.stringify(menus) }}
|
||||||
|
</div>
|
||||||
|
<button @click="unifiedLoginSDK.logout()">退出</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import {type RouterInfo, unifiedLoginSDK, type UserInfo} from "oauth2-login-sdk";
|
||||||
|
|
||||||
|
const userInfo = ref<UserInfo | null>(null);
|
||||||
|
const menus = ref<RouterInfo | null>(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 在组件挂载后获取菜单
|
||||||
|
onMounted(async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
// 同步获取用户信息
|
||||||
|
userInfo.value = unifiedLoginSDK.getUserInfo();
|
||||||
|
menus.value = await unifiedLoginSDK.getRoutes();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch menus:', error);
|
||||||
|
menus.value = null;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
18
demo/frontend/src/main.ts
Normal file
18
demo/frontend/src/main.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import './style.css'
|
||||||
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
import unifiedLoginSDK from "oauth2-login-sdk";
|
||||||
|
|
||||||
|
// 初始化配置
|
||||||
|
unifiedLoginSDK.init({
|
||||||
|
clientId: 'b55c88c20db94790a60a5075',
|
||||||
|
registrationId: 'demo',
|
||||||
|
storageType: 'localStorage',
|
||||||
|
basepath: '/demo-api',
|
||||||
|
idpLogoutUrl: 'http://localhost/logout',
|
||||||
|
homePage: 'http://localhost:9506/home'
|
||||||
|
});
|
||||||
|
const app = createApp(App)
|
||||||
|
app.use(router)
|
||||||
|
app.mount('#app')
|
||||||
31
demo/frontend/src/router/index.ts
Normal file
31
demo/frontend/src/router/index.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import unifiedLoginSDK from 'oauth2-login-sdk';
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'home',
|
||||||
|
redirect: '/home'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'home',
|
||||||
|
component: () => import('../components/Home.vue')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
router.beforeEach(async (to, _from, next) => {
|
||||||
|
debugger
|
||||||
|
if (!unifiedLoginSDK.isAuthenticated()) {
|
||||||
|
if (to.path === '/oauth2/callback') {
|
||||||
|
await unifiedLoginSDK.handleCallback()
|
||||||
|
}else{
|
||||||
|
await unifiedLoginSDK.login()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
79
demo/frontend/src/style.css
Normal file
79
demo/frontend/src/style.css
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
:root {
|
||||||
|
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
color-scheme: light dark;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
background-color: #242424;
|
||||||
|
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #646cff;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #535bf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
min-width: 320px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3.2em;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: 0.6em 1.2em;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: inherit;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.25s;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
border-color: #646cff;
|
||||||
|
}
|
||||||
|
button:focus,
|
||||||
|
button:focus-visible {
|
||||||
|
outline: 4px auto -webkit-focus-ring-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
:root {
|
||||||
|
color: #213547;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #747bff;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
demo/frontend/tsconfig.app.json
Normal file
16
demo/frontend/tsconfig.app.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
"types": ["vite/client"],
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"erasableSyntaxOnly": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||||
|
}
|
||||||
7
demo/frontend/tsconfig.json
Normal file
7
demo/frontend/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig.app.json" },
|
||||||
|
{ "path": "./tsconfig.node.json" }
|
||||||
|
]
|
||||||
|
}
|
||||||
26
demo/frontend/tsconfig.node.json
Normal file
26
demo/frontend/tsconfig.node.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||||
|
"target": "ES2023",
|
||||||
|
"lib": ["ES2023"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"types": ["node"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"erasableSyntaxOnly": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
||||||
85
demo/frontend/vite.config.ts
Normal file
85
demo/frontend/vite.config.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { defineConfig, loadEnv } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import { resolve } from 'path'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig(({ mode }) => {
|
||||||
|
// 加载环境变量
|
||||||
|
const env = loadEnv(mode, process.cwd(), '')
|
||||||
|
|
||||||
|
// 定义基础 URL,支持环境变量
|
||||||
|
const baseUrl = env.VITE_API_BASE_URL || 'http://localhost:10001'
|
||||||
|
const apiPrefix = env.VITE_API_PREFIX || '/demo-api'
|
||||||
|
|
||||||
|
return {
|
||||||
|
plugins: [vue()],
|
||||||
|
|
||||||
|
// 基础路径
|
||||||
|
base: env.VITE_BASE_PATH || '/',
|
||||||
|
|
||||||
|
// 解析配置
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
|
extensions: ['.js', '.ts', '.jsx', '.tsx', '.vue', '.json']
|
||||||
|
},
|
||||||
|
|
||||||
|
// 开发服务器配置
|
||||||
|
server: {
|
||||||
|
port: 9506,
|
||||||
|
host: true, // 监听所有地址
|
||||||
|
open: true, // 自动打开浏览器
|
||||||
|
cors: true, // 启用 CORS
|
||||||
|
|
||||||
|
// 代理配置
|
||||||
|
proxy: {
|
||||||
|
// API 代理(修正了 rewrite 路径)
|
||||||
|
[apiPrefix]: {
|
||||||
|
target: baseUrl,
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(new RegExp(`^${apiPrefix}`), '')
|
||||||
|
},
|
||||||
|
|
||||||
|
// WebSocket 代理(如果需要)
|
||||||
|
'/ws': {
|
||||||
|
target: baseUrl.replace('http', 'ws'),
|
||||||
|
ws: true,
|
||||||
|
changeOrigin: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 构建配置
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
sourcemap: mode !== 'production',
|
||||||
|
chunkSizeWarningLimit: 1600,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks: {
|
||||||
|
vue: ['vue', 'vue-router', 'vuex/pinia'],
|
||||||
|
vendor: ['axios', 'lodash', 'dayjs'],
|
||||||
|
ui: ['element-plus', 'ant-design-vue'] // 根据实际使用的 UI 库调整
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 预览配置
|
||||||
|
preview: {
|
||||||
|
port: 9507,
|
||||||
|
host: true,
|
||||||
|
open: true
|
||||||
|
},
|
||||||
|
|
||||||
|
// CSS 配置
|
||||||
|
css: {
|
||||||
|
preprocessorOptions: {
|
||||||
|
scss: {
|
||||||
|
additionalData: `@import "@/styles/variables.scss";`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
2
idp/backend/idp-starter/.gitattributes
vendored
Normal file
2
idp/backend/idp-starter/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/mvnw text eol=lf
|
||||||
|
*.cmd text eol=crlf
|
||||||
33
idp/backend/idp-starter/.gitignore
vendored
Normal file
33
idp/backend/idp-starter/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
295
idp/backend/idp-starter/mvnw
vendored
Normal file
295
idp/backend/idp-starter/mvnw
vendored
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Apache Maven Wrapper startup batch script, version 3.3.4
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||||
|
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
set -euf
|
||||||
|
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||||
|
|
||||||
|
# OS specific support.
|
||||||
|
native_path() { printf %s\\n "$1"; }
|
||||||
|
case "$(uname)" in
|
||||||
|
CYGWIN* | MINGW*)
|
||||||
|
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||||
|
native_path() { cygpath --path --windows "$1"; }
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# set JAVACMD and JAVACCMD
|
||||||
|
set_java_home() {
|
||||||
|
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||||
|
if [ -n "${JAVA_HOME-}" ]; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||||
|
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||||
|
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v java
|
||||||
|
)" || :
|
||||||
|
JAVACCMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v javac
|
||||||
|
)" || :
|
||||||
|
|
||||||
|
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||||
|
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# hash string like Java String::hashCode
|
||||||
|
hash_string() {
|
||||||
|
str="${1:-}" h=0
|
||||||
|
while [ -n "$str" ]; do
|
||||||
|
char="${str%"${str#?}"}"
|
||||||
|
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||||
|
str="${str#?}"
|
||||||
|
done
|
||||||
|
printf %x\\n $h
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose() { :; }
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf %s\\n "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
# MWRAPPER-139:
|
||||||
|
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||||
|
# Needed for removing poorly interpreted newline sequences when running in more
|
||||||
|
# exotic environments such as mingw bash on Windows.
|
||||||
|
printf "%s" "${1}" | tr -d '[:space:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptDir="$(dirname "$0")"
|
||||||
|
scriptName="$(basename "$0")"
|
||||||
|
|
||||||
|
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
while IFS="=" read -r key value; do
|
||||||
|
case "${key-}" in
|
||||||
|
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||||
|
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||||
|
esac
|
||||||
|
done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
|
||||||
|
case "${distributionUrl##*/}" in
|
||||||
|
maven-mvnd-*bin.*)
|
||||||
|
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||||
|
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||||
|
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||||
|
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||||
|
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||||
|
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||||
|
*)
|
||||||
|
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||||
|
distributionPlatform=linux-amd64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||||
|
;;
|
||||||
|
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||||
|
*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||||
|
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||||
|
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||||
|
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||||
|
|
||||||
|
exec_maven() {
|
||||||
|
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||||
|
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -d "$MAVEN_HOME" ]; then
|
||||||
|
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
exec_maven "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${distributionUrl-}" in
|
||||||
|
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||||
|
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||||
|
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||||
|
trap clean HUP INT TERM EXIT
|
||||||
|
else
|
||||||
|
die "cannot create temp dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
verbose "Downloading from: $distributionUrl"
|
||||||
|
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
# select .zip or .tar.gz
|
||||||
|
if ! command -v unzip >/dev/null; then
|
||||||
|
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# verbose opt
|
||||||
|
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||||
|
|
||||||
|
# normalize http auth
|
||||||
|
case "${MVNW_PASSWORD:+has-password}" in
|
||||||
|
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||||
|
verbose "Found wget ... using wget"
|
||||||
|
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||||
|
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||||
|
verbose "Found curl ... using curl"
|
||||||
|
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||||
|
elif set_java_home; then
|
||||||
|
verbose "Falling back to use Java to download"
|
||||||
|
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||||
|
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
cat >"$javaSource" <<-END
|
||||||
|
public class Downloader extends java.net.Authenticator
|
||||||
|
{
|
||||||
|
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||||
|
{
|
||||||
|
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||||
|
}
|
||||||
|
public static void main( String[] args ) throws Exception
|
||||||
|
{
|
||||||
|
setDefault( new Downloader() );
|
||||||
|
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END
|
||||||
|
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||||
|
verbose " - Compiling Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||||
|
verbose " - Running Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
if [ -n "${distributionSha256Sum-}" ]; then
|
||||||
|
distributionSha256Result=false
|
||||||
|
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||||
|
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||||
|
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
elif command -v sha256sum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
elif command -v shasum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||||
|
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $distributionSha256Result = false ]; then
|
||||||
|
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||||
|
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
if command -v unzip >/dev/null; then
|
||||||
|
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||||
|
else
|
||||||
|
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find the actual extracted directory name (handles snapshots where filename != directory name)
|
||||||
|
actualDistributionDir=""
|
||||||
|
|
||||||
|
# First try the expected directory name (for regular distributions)
|
||||||
|
if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
|
||||||
|
if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
|
||||||
|
actualDistributionDir="$distributionUrlNameMain"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If not found, search for any directory with the Maven executable (for snapshots)
|
||||||
|
if [ -z "$actualDistributionDir" ]; then
|
||||||
|
# enable globbing to iterate over items
|
||||||
|
set +f
|
||||||
|
for dir in "$TMP_DOWNLOAD_DIR"/*; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
if [ -f "$dir/bin/$MVN_CMD" ]; then
|
||||||
|
actualDistributionDir="$(basename "$dir")"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
set -f
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$actualDistributionDir" ]; then
|
||||||
|
verbose "Contents of $TMP_DOWNLOAD_DIR:"
|
||||||
|
verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
|
||||||
|
die "Could not find Maven distribution directory in extracted archive"
|
||||||
|
fi
|
||||||
|
|
||||||
|
verbose "Found extracted Maven distribution directory: $actualDistributionDir"
|
||||||
|
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
|
||||||
|
mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||||
|
|
||||||
|
clean || :
|
||||||
|
exec_maven "$@"
|
||||||
189
idp/backend/idp-starter/mvnw.cmd
vendored
Normal file
189
idp/backend/idp-starter/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
<# : batch portion
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Apache Maven Wrapper startup batch script, version 3.3.4
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||||
|
@SET __MVNW_CMD__=
|
||||||
|
@SET __MVNW_ERROR__=
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||||
|
@SET PSModulePath=
|
||||||
|
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||||
|
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||||
|
)
|
||||||
|
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=
|
||||||
|
@SET __MVNW_ARG0_NAME__=
|
||||||
|
@SET MVNW_USERNAME=
|
||||||
|
@SET MVNW_PASSWORD=
|
||||||
|
@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*)
|
||||||
|
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||||
|
@GOTO :EOF
|
||||||
|
: end batch / begin powershell #>
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
if ($env:MVNW_VERBOSE -eq "true") {
|
||||||
|
$VerbosePreference = "Continue"
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||||
|
if (!$distributionUrl) {
|
||||||
|
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||||
|
"maven-mvnd-*" {
|
||||||
|
$USE_MVND = $true
|
||||||
|
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||||
|
$MVN_CMD = "mvnd.cmd"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
$USE_MVND = $false
|
||||||
|
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
if ($env:MVNW_REPOURL) {
|
||||||
|
$MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||||
|
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')"
|
||||||
|
}
|
||||||
|
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||||
|
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||||
|
|
||||||
|
$MAVEN_M2_PATH = "$HOME/.m2"
|
||||||
|
if ($env:MAVEN_USER_HOME) {
|
||||||
|
$MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
|
||||||
|
New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
$MAVEN_WRAPPER_DISTS = $null
|
||||||
|
if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
|
||||||
|
$MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
|
||||||
|
} else {
|
||||||
|
$MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
|
||||||
|
}
|
||||||
|
|
||||||
|
$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
|
||||||
|
$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||||
|
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||||
|
|
||||||
|
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||||
|
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
exit $?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||||
|
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||||
|
}
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||||
|
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||||
|
trap {
|
||||||
|
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
Write-Verbose "Downloading from: $distributionUrl"
|
||||||
|
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||||
|
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||||
|
}
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||||
|
if ($distributionSha256Sum) {
|
||||||
|
if ($USE_MVND) {
|
||||||
|
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||||
|
}
|
||||||
|
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||||
|
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||||
|
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||||
|
|
||||||
|
# Find the actual extracted directory name (handles snapshots where filename != directory name)
|
||||||
|
$actualDistributionDir = ""
|
||||||
|
|
||||||
|
# First try the expected directory name (for regular distributions)
|
||||||
|
$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
|
||||||
|
$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
|
||||||
|
if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
|
||||||
|
$actualDistributionDir = $distributionUrlNameMain
|
||||||
|
}
|
||||||
|
|
||||||
|
# If not found, search for any directory with the Maven executable (for snapshots)
|
||||||
|
if (!$actualDistributionDir) {
|
||||||
|
Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
|
||||||
|
$testPath = Join-Path $_.FullName "bin/$MVN_CMD"
|
||||||
|
if (Test-Path -Path $testPath -PathType Leaf) {
|
||||||
|
$actualDistributionDir = $_.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$actualDistributionDir) {
|
||||||
|
Write-Error "Could not find Maven distribution directory in extracted archive"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
|
||||||
|
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||||
|
try {
|
||||||
|
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||||
|
} catch {
|
||||||
|
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||||
|
Write-Error "fail to move MAVEN_HOME"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
168
idp/backend/idp-starter/pom.xml
Normal file
168
idp/backend/idp-starter/pom.xml
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.5.10</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>org.lingniu</groupId>
|
||||||
|
<artifactId>idp-starter</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>idp-starter</name>
|
||||||
|
<description>idp-starter</description>
|
||||||
|
<url/>
|
||||||
|
<licenses>
|
||||||
|
<license/>
|
||||||
|
</licenses>
|
||||||
|
<developers>
|
||||||
|
<developer/>
|
||||||
|
</developers>
|
||||||
|
<scm>
|
||||||
|
<connection/>
|
||||||
|
<developerConnection/>
|
||||||
|
<tag/>
|
||||||
|
<url/>
|
||||||
|
</scm>
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
<spring-security-oauth2.version>1.5.5</spring-security-oauth2.version>
|
||||||
|
<mysql.version>8.0.33</mysql.version>
|
||||||
|
<mybatis-plus.version>3.5.10</mybatis-plus.version>
|
||||||
|
<hutool.version>5.8.40</hutool.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.session</groupId>
|
||||||
|
<artifactId>spring-session-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Tools -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>${hutool.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<version>2.19.4</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.19.4</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.20.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
<artifactId>fastjson2</artifactId>
|
||||||
|
<version>2.0.60</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>pro.fessional</groupId>
|
||||||
|
<artifactId>kaptcha</artifactId>
|
||||||
|
<version>2.3.3</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>nl.basjes.parse.useragent</groupId>
|
||||||
|
<artifactId>yauaa</artifactId>
|
||||||
|
<version>7.32.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>${mysql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.nimbusds</groupId>
|
||||||
|
<artifactId>nimbus-jose-jwt</artifactId>
|
||||||
|
<version>10.0.2</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.lingniu.idp;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@MapperScan("org.lingniu.**.mapper")
|
||||||
|
public class IdpStarterApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(IdpStarterApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.lingniu.idp.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匿名访问不鉴权注解
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Anonymous
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.lingniu.idp.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据权限过滤注解
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface DataScope
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 部门表的别名
|
||||||
|
*/
|
||||||
|
public String deptAlias() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户表的别名
|
||||||
|
*/
|
||||||
|
public String userAlias() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
|
||||||
|
*/
|
||||||
|
public String permission() default "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.lingniu.idp.annotation;
|
||||||
|
|
||||||
|
import org.lingniu.idp.enums.DataSourceType;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义多数据源切换注解
|
||||||
|
*
|
||||||
|
* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Inherited
|
||||||
|
public @interface DataSource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 切换数据源名称
|
||||||
|
*/
|
||||||
|
public DataSourceType value() default DataSourceType.MASTER;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package org.lingniu.idp.annotation;
|
||||||
|
|
||||||
|
import org.lingniu.idp.enums.BusinessType;
|
||||||
|
import org.lingniu.idp.enums.OperatorType;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义操作日志记录注解
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Target({ ElementType.PARAMETER, ElementType.METHOD })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Log
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 模块
|
||||||
|
*/
|
||||||
|
public String title() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能
|
||||||
|
*/
|
||||||
|
public BusinessType businessType() default BusinessType.OTHER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作人类别
|
||||||
|
*/
|
||||||
|
public OperatorType operatorType() default OperatorType.MANAGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否保存请求的参数
|
||||||
|
*/
|
||||||
|
public boolean isSaveRequestData() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否保存响应的参数
|
||||||
|
*/
|
||||||
|
public boolean isSaveResponseData() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排除指定的请求参数
|
||||||
|
*/
|
||||||
|
public String[] excludeParamNames() default {};
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.lingniu.idp.annotation;
|
||||||
|
|
||||||
|
import org.lingniu.idp.constant.CacheConstants;
|
||||||
|
import org.lingniu.idp.enums.LimitType;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流注解
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface RateLimiter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 限流key
|
||||||
|
*/
|
||||||
|
public String key() default CacheConstants.RATE_LIMIT_KEY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流时间,单位秒
|
||||||
|
*/
|
||||||
|
public int time() default 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流次数
|
||||||
|
*/
|
||||||
|
public int count() default 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流类型
|
||||||
|
*/
|
||||||
|
public LimitType limitType() default LimitType.DEFAULT;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.lingniu.idp.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义注解防止表单重复提交
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface RepeatSubmit
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 间隔时间(ms),小于此时间视为重复提交
|
||||||
|
*/
|
||||||
|
public int interval() default 5000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示消息
|
||||||
|
*/
|
||||||
|
public String message() default "不允许重复提交,请稍候再试";
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.lingniu.idp.annotation;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import org.lingniu.idp.config.serializer.SensitiveJsonSerializer;
|
||||||
|
import org.lingniu.idp.enums.DesensitizedType;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据脱敏注解
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@JacksonAnnotationsInside
|
||||||
|
@JsonSerialize(using = SensitiveJsonSerializer.class)
|
||||||
|
public @interface Sensitive
|
||||||
|
{
|
||||||
|
DesensitizedType desensitizedType();
|
||||||
|
}
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
package org.lingniu.idp.common.redis;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.BoundSetOperations;
|
||||||
|
import org.springframework.data.redis.core.HashOperations;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.ValueOperations;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring redis 工具类
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
**/
|
||||||
|
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||||
|
@Component
|
||||||
|
public class RedisCache
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
public RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存基本的对象,Integer、String、实体类等
|
||||||
|
*
|
||||||
|
* @param key 缓存的键值
|
||||||
|
* @param value 缓存的值
|
||||||
|
*/
|
||||||
|
public <T> void setCacheObject(final String key, final T value)
|
||||||
|
{
|
||||||
|
redisTemplate.opsForValue().set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存基本的对象,Integer、String、实体类等
|
||||||
|
*
|
||||||
|
* @param key 缓存的键值
|
||||||
|
* @param value 缓存的值
|
||||||
|
* @param timeout 时间
|
||||||
|
* @param timeUnit 时间颗粒度
|
||||||
|
*/
|
||||||
|
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
|
||||||
|
{
|
||||||
|
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置有效时间
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @param timeout 超时时间
|
||||||
|
* @return true=设置成功;false=设置失败
|
||||||
|
*/
|
||||||
|
public boolean expire(final String key, final long timeout)
|
||||||
|
{
|
||||||
|
return expire(key, timeout, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置有效时间
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @param timeout 超时时间
|
||||||
|
* @param unit 时间单位
|
||||||
|
* @return true=设置成功;false=设置失败
|
||||||
|
*/
|
||||||
|
public boolean expire(final String key, final long timeout, final TimeUnit unit)
|
||||||
|
{
|
||||||
|
return redisTemplate.expire(key, timeout, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取有效时间
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @return 有效时间
|
||||||
|
*/
|
||||||
|
public long getExpire(final String key)
|
||||||
|
{
|
||||||
|
return redisTemplate.getExpire(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断 key是否存在
|
||||||
|
*
|
||||||
|
* @param key 键
|
||||||
|
* @return true 存在 false不存在
|
||||||
|
*/
|
||||||
|
public Boolean hasKey(String key)
|
||||||
|
{
|
||||||
|
return redisTemplate.hasKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得缓存的基本对象。
|
||||||
|
*
|
||||||
|
* @param key 缓存键值
|
||||||
|
* @return 缓存键值对应的数据
|
||||||
|
*/
|
||||||
|
public <T> T getCacheObject(final String key)
|
||||||
|
{
|
||||||
|
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||||
|
return operation.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除单个对象
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
public boolean deleteObject(final String key)
|
||||||
|
{
|
||||||
|
return redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除集合对象
|
||||||
|
*
|
||||||
|
* @param collection 多个对象
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean deleteObject(final Collection collection)
|
||||||
|
{
|
||||||
|
return redisTemplate.delete(collection) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存List数据
|
||||||
|
*
|
||||||
|
* @param key 缓存的键值
|
||||||
|
* @param dataList 待缓存的List数据
|
||||||
|
* @return 缓存的对象
|
||||||
|
*/
|
||||||
|
public <T> long setCacheList(final String key, final List<T> dataList)
|
||||||
|
{
|
||||||
|
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
|
||||||
|
return count == null ? 0 : count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得缓存的list对象
|
||||||
|
*
|
||||||
|
* @param key 缓存的键值
|
||||||
|
* @return 缓存键值对应的数据
|
||||||
|
*/
|
||||||
|
public <T> List<T> getCacheList(final String key)
|
||||||
|
{
|
||||||
|
return redisTemplate.opsForList().range(key, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存Set
|
||||||
|
*
|
||||||
|
* @param key 缓存键值
|
||||||
|
* @param dataSet 缓存的数据
|
||||||
|
* @return 缓存数据的对象
|
||||||
|
*/
|
||||||
|
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
|
||||||
|
{
|
||||||
|
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
|
||||||
|
Iterator<T> it = dataSet.iterator();
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
setOperation.add(it.next());
|
||||||
|
}
|
||||||
|
return setOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得缓存的set
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <T> Set<T> getCacheSet(final String key)
|
||||||
|
{
|
||||||
|
return redisTemplate.opsForSet().members(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存Map
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param dataMap
|
||||||
|
*/
|
||||||
|
public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
|
||||||
|
{
|
||||||
|
if (dataMap != null) {
|
||||||
|
redisTemplate.opsForHash().putAll(key, dataMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得缓存的Map
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <T> Map<String, T> getCacheMap(final String key)
|
||||||
|
{
|
||||||
|
return redisTemplate.opsForHash().entries(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 往Hash中存入数据
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @param hKey Hash键
|
||||||
|
* @param value 值
|
||||||
|
*/
|
||||||
|
public <T> void setCacheMapValue(final String key, final String hKey, final T value)
|
||||||
|
{
|
||||||
|
redisTemplate.opsForHash().put(key, hKey, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Hash中的数据
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @param hKey Hash键
|
||||||
|
* @return Hash中的对象
|
||||||
|
*/
|
||||||
|
public <T> T getCacheMapValue(final String key, final String hKey)
|
||||||
|
{
|
||||||
|
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
|
||||||
|
return opsForHash.get(key, hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取多个Hash中的数据
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @param hKeys Hash键集合
|
||||||
|
* @return Hash对象集合
|
||||||
|
*/
|
||||||
|
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
|
||||||
|
{
|
||||||
|
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Hash中的某条数据
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @param hKey Hash键
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean deleteCacheMapValue(final String key, final String hKey)
|
||||||
|
{
|
||||||
|
return redisTemplate.opsForHash().delete(key, hKey) > 0;
|
||||||
|
}
|
||||||
|
public boolean deleteCacheSetValue(final String key, final String hKey)
|
||||||
|
{
|
||||||
|
return redisTemplate.opsForSet().remove(key, hKey) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得缓存的基本对象列表
|
||||||
|
*
|
||||||
|
* @param pattern 字符串前缀
|
||||||
|
* @return 对象列表
|
||||||
|
*/
|
||||||
|
public Collection<String> keys(final String pattern)
|
||||||
|
{
|
||||||
|
return redisTemplate.keys(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheSet(String key, String value) {
|
||||||
|
redisTemplate.opsForSet().add(key,value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.lingniu.idp.common.xss;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.validation.Constraint;
|
||||||
|
import jakarta.validation.Payload;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义xss校验注解
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
|
||||||
|
@Constraint(validatedBy = { XssValidator.class })
|
||||||
|
public @interface Xss
|
||||||
|
{
|
||||||
|
String message()
|
||||||
|
|
||||||
|
default "不允许任何脚本运行";
|
||||||
|
|
||||||
|
Class<?>[] groups() default {};
|
||||||
|
|
||||||
|
Class<? extends Payload>[] payload() default {};
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.lingniu.idp.common.xss;
|
||||||
|
|
||||||
|
import jakarta.validation.ConstraintValidator;
|
||||||
|
import jakarta.validation.ConstraintValidatorContext;
|
||||||
|
import org.lingniu.idp.utils.StringUtils;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义xss校验注解实现
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class XssValidator implements ConstraintValidator<Xss, String>
|
||||||
|
{
|
||||||
|
private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)
|
||||||
|
{
|
||||||
|
if (StringUtils.isBlank(value))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !containsHtml(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean containsHtml(String value)
|
||||||
|
{
|
||||||
|
StringBuilder sHtml = new StringBuilder();
|
||||||
|
Pattern pattern = Pattern.compile(HTML_PATTERN);
|
||||||
|
Matcher matcher = pattern.matcher(value);
|
||||||
|
while (matcher.find())
|
||||||
|
{
|
||||||
|
sHtml.append(matcher.group());
|
||||||
|
}
|
||||||
|
return pattern.matcher(sHtml).matches();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import com.nimbusds.jose.jwk.JWKSet;
|
||||||
|
import com.nimbusds.jose.jwk.RSAKey;
|
||||||
|
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
|
||||||
|
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||||
|
import com.nimbusds.jose.proc.SecurityContext;
|
||||||
|
import org.lingniu.idp.enums.CustomScopes;
|
||||||
|
import org.lingniu.idp.security.filter.IdpAuthenticationFilter;
|
||||||
|
import org.lingniu.idp.security.granttype.SmsCodeGrantType;
|
||||||
|
import org.lingniu.idp.security.handler.Oauth2CodeSuccessHandler;
|
||||||
|
import org.lingniu.idp.service.core.UserDetailsServiceImpl;
|
||||||
|
import org.lingniu.idp.service.core.login.IdpTokenService;
|
||||||
|
import org.lingniu.idp.service.core.login.LoginService;
|
||||||
|
import org.lingniu.idp.service.core.login.RedisAccessTokenService;
|
||||||
|
import org.lingniu.idp.utils.jwt.Jwks;
|
||||||
|
import org.lingniu.idp.utils.jwt.JwtUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationContext;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
|
||||||
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||||
|
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||||
|
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||||
|
|
||||||
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer.authorizationServer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class AuthorizationServerConfig {
|
||||||
|
|
||||||
|
// @Autowired
|
||||||
|
// private SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;
|
||||||
|
private static final String CUSTOM_CONSENT_PAGE_URI = "http://localhost/oauth2/consent";
|
||||||
|
@Autowired
|
||||||
|
private JwtUtil jwtUtil;
|
||||||
|
@Autowired
|
||||||
|
private IdpTokenService idpTokenService;
|
||||||
|
@Autowired
|
||||||
|
private UserDetailsServiceImpl userDetailsService;
|
||||||
|
@Autowired
|
||||||
|
private OidcUserInfoMapper oidcUserInfoMapper;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(1)
|
||||||
|
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = authorizationServer();
|
||||||
|
http
|
||||||
|
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
|
||||||
|
.with(authorizationServerConfigurer, (authorizationServer) ->
|
||||||
|
authorizationServer
|
||||||
|
.authorizationEndpoint(authorizationEndpoint ->
|
||||||
|
authorizationEndpoint.consentPage(CUSTOM_CONSENT_PAGE_URI)
|
||||||
|
.authorizationResponseHandler(new Oauth2CodeSuccessHandler())
|
||||||
|
)
|
||||||
|
.tokenEndpoint(oAuth2TokenEndpointConfigurer -> {})
|
||||||
|
.oidc(Customizer.withDefaults())
|
||||||
|
.oidc(oidcConfigurer ->
|
||||||
|
oidcConfigurer.userInfoEndpoint(oidcUserInfoEndpointConfigurer ->
|
||||||
|
oidcUserInfoEndpointConfigurer.userInfoMapper(oidcUserInfoMapper)
|
||||||
|
)
|
||||||
|
) // Enable OpenID Connect 1.0
|
||||||
|
)
|
||||||
|
.addFilterAfter(jwtAuthenticationFilter(), LogoutFilter.class)
|
||||||
|
.oauth2ResourceServer(oauth2ResourceServer ->
|
||||||
|
oauth2ResourceServer.jwt(Customizer.withDefaults()))
|
||||||
|
.authorizeHttpRequests((authorize) ->
|
||||||
|
authorize.anyRequest().authenticated()
|
||||||
|
)
|
||||||
|
// Redirect to the /login page when not authenticated from the authorization endpoint
|
||||||
|
// NOTE: DefaultSecurityConfig is configured with formLogin.loginPage("/login")
|
||||||
|
.exceptionHandling((exceptions) -> exceptions
|
||||||
|
.defaultAuthenticationEntryPointFor(
|
||||||
|
new LoginUrlAuthenticationEntryPoint("http://localhost/login"),
|
||||||
|
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
public JdbcRegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
|
||||||
|
RegisteredClient client = RegisteredClient.withId("68dc155a-1034-4cd8-91dc-fca206e2f6d3")
|
||||||
|
.clientId("2c6f1d9ff78641c78d72a848")
|
||||||
|
//l3X95am7RaX8-Uu9-5nDYmD9-OFU-8_GHmkfnKfaS_0
|
||||||
|
.clientSecret("{bcrypt}$2a$10$JDoQUK5aWvYiZZDpgSC8k.qPGfqbYtXAF5H1IW/e2quGWA8Zr6ffq")
|
||||||
|
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||||
|
.authorizationGrantType(SmsCodeGrantType.SMS_CODE) // 添加自定义Grant Type
|
||||||
|
.clientName("PORTAL")
|
||||||
|
.redirectUri("http://localhost:81/callback")
|
||||||
|
.scope(OidcScopes.OPENID)
|
||||||
|
.scope(OidcScopes.PROFILE)
|
||||||
|
.scope(CustomScopes.PERMS.name().toLowerCase())
|
||||||
|
.tokenSettings(TokenSettings.builder().accessTokenTimeToLive(Duration.ofHours(12)).refreshTokenTimeToLive(Duration.ofDays(7)).build())
|
||||||
|
.scope("message.read")
|
||||||
|
.scope("message.write")
|
||||||
|
.build();
|
||||||
|
RegisteredClient demo = RegisteredClient.withId("c81008aa-b33f-4ebc-bba7-3c6d0eee23b9")
|
||||||
|
.clientId("b55c88c20db94790a60a5075")
|
||||||
|
//l3X95am7RaX8-Uu9-5nDYmD9-OFU-8_GHmkfnKfaS_0
|
||||||
|
.clientSecret("{bcrypt}$2a$10$gLsAsObi5ffOddmkf5YchOtT3olfcAmSTt75X6H/mHBVYf8DXnIwi")
|
||||||
|
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||||
|
.authorizationGrantType(SmsCodeGrantType.SMS_CODE) // 添加自定义Grant Type
|
||||||
|
.clientName("DEMO")
|
||||||
|
.redirectUri("http://localhost:9506/oauth2/callback")
|
||||||
|
.scope(OidcScopes.OPENID)
|
||||||
|
.scope(OidcScopes.PROFILE)
|
||||||
|
.scope(CustomScopes.PERMS.name().toLowerCase())
|
||||||
|
.tokenSettings(TokenSettings.builder().accessTokenTimeToLive(Duration.ofHours(12)).refreshTokenTimeToLive(Duration.ofDays(7)).build())
|
||||||
|
.scope("read")
|
||||||
|
.scope("write")
|
||||||
|
.build();
|
||||||
|
// Save registered client's in db as if in-memory
|
||||||
|
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
|
||||||
|
registeredClientRepository.save(client);
|
||||||
|
registeredClientRepository.save(demo);
|
||||||
|
return registeredClientRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Bean
|
||||||
|
// public OAuth2TokenGenerator<?> tokenGenerator(CustomAccessTokenGenerator accessTokenGenerator,OAuth2RefreshTokenGenerator refreshTokenGenerator) {
|
||||||
|
// CustomAccessTokenGenerator accessTokenGenerator = new CustomAccessTokenGenerator();
|
||||||
|
// OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
||||||
|
// return new DelegatingOAuth2TokenGenerator(
|
||||||
|
// accessTokenGenerator, refreshTokenGenerator
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
@Bean
|
||||||
|
public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate) {
|
||||||
|
return new JdbcOAuth2AuthorizationService(jdbcTemplate,registeredClientRepository(jdbcTemplate));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义JWT认证过滤器
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public IdpAuthenticationFilter jwtAuthenticationFilter() {
|
||||||
|
return new IdpAuthenticationFilter(idpTokenService,userDetailsService);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 主JWK源,使用应用配置的RSA密钥
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public JWKSource<SecurityContext> jwkSource() {
|
||||||
|
try {
|
||||||
|
// 从JwtUtil中获取密钥
|
||||||
|
RSAPublicKey publicKey = jwtUtil.getPublicKey();
|
||||||
|
RSAPrivateKey privateKey = jwtUtil.getPrivateKey();
|
||||||
|
|
||||||
|
// 创建RSA JWK,包含私钥(用于签名)
|
||||||
|
RSAKey rsaKey = Jwks.generateRsa(
|
||||||
|
publicKey,
|
||||||
|
privateKey,
|
||||||
|
"idp" // 密钥ID
|
||||||
|
);
|
||||||
|
|
||||||
|
JWKSet jwkSet = new JWKSet(rsaKey);
|
||||||
|
|
||||||
|
// 使用ImmutableJWKSet包装
|
||||||
|
return new ImmutableJWKSet<>(jwkSet);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("初始化JWK源失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
|
||||||
|
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
||||||
|
import com.google.code.kaptcha.util.Config;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import static com.google.code.kaptcha.Constants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码配置
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class CaptchaConfig
|
||||||
|
{
|
||||||
|
@Bean(name = "captchaProducer")
|
||||||
|
public DefaultKaptcha getKaptchaBean()
|
||||||
|
{
|
||||||
|
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||||
|
Properties properties = new Properties();
|
||||||
|
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||||
|
properties.setProperty(KAPTCHA_BORDER, "yes");
|
||||||
|
// 验证码文本字符颜色 默认为Color.BLACK
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
|
||||||
|
// 验证码图片宽度 默认为200
|
||||||
|
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
||||||
|
// 验证码图片高度 默认为50
|
||||||
|
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
||||||
|
// 验证码文本字符大小 默认为40
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
|
||||||
|
// KAPTCHA_SESSION_KEY
|
||||||
|
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
|
||||||
|
// 验证码文本字符长度 默认为5
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
|
||||||
|
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
||||||
|
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
||||||
|
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
||||||
|
Config config = new Config(properties);
|
||||||
|
defaultKaptcha.setConfig(config);
|
||||||
|
return defaultKaptcha;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "captchaProducerMath")
|
||||||
|
public DefaultKaptcha getKaptchaBeanMath()
|
||||||
|
{
|
||||||
|
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||||
|
Properties properties = new Properties();
|
||||||
|
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||||
|
properties.setProperty(KAPTCHA_BORDER, "yes");
|
||||||
|
// 边框颜色 默认为Color.BLACK
|
||||||
|
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
|
||||||
|
// 验证码文本字符颜色 默认为Color.BLACK
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
|
||||||
|
// 验证码图片宽度 默认为200
|
||||||
|
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
||||||
|
// 验证码图片高度 默认为50
|
||||||
|
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
||||||
|
// 验证码文本字符大小 默认为40
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
|
||||||
|
// KAPTCHA_SESSION_KEY
|
||||||
|
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
|
||||||
|
// 验证码文本生成器
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "org.lingniu.idp.config.KaptchaTextCreator");
|
||||||
|
// 验证码文本字符间距 默认为2
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
|
||||||
|
// 验证码文本字符长度 默认为5
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
|
||||||
|
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||||
|
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
||||||
|
// 验证码噪点颜色 默认为Color.BLACK
|
||||||
|
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
|
||||||
|
// 干扰实现类
|
||||||
|
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
|
||||||
|
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
||||||
|
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
||||||
|
Config config = new Config(properties);
|
||||||
|
defaultKaptcha.setConfig(config);
|
||||||
|
return defaultKaptcha;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import org.lingniu.idp.constant.Constants;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.LocaleResolver;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||||
|
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源文件配置加载
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class I18nConfig implements WebMvcConfigurer
|
||||||
|
{
|
||||||
|
@Bean
|
||||||
|
public LocaleResolver localeResolver()
|
||||||
|
{
|
||||||
|
SessionLocaleResolver slr = new SessionLocaleResolver();
|
||||||
|
// 默认语言
|
||||||
|
slr.setDefaultLocale(Constants.DEFAULT_LOCALE);
|
||||||
|
return slr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LocaleChangeInterceptor localeChangeInterceptor()
|
||||||
|
{
|
||||||
|
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
|
||||||
|
// 参数名
|
||||||
|
lci.setParamName("lang");
|
||||||
|
return lci;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry)
|
||||||
|
{
|
||||||
|
registry.addInterceptor(localeChangeInterceptor());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "idp.jwt")
|
||||||
|
public class JwtProperties {
|
||||||
|
|
||||||
|
// 令牌配置
|
||||||
|
private String header = "Authorization";
|
||||||
|
private String prefix = "Bearer ";
|
||||||
|
private Duration expiration = Duration.ofHours(1);
|
||||||
|
private Duration refreshExpiration = Duration.ofDays(7);
|
||||||
|
|
||||||
|
// RSA 密钥配置(支持文件路径或直接内容)
|
||||||
|
private RsaKey rsa = new RsaKey();
|
||||||
|
|
||||||
|
// RSA 密钥内部类
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public static class RsaKey {
|
||||||
|
// Getter 和 Setter
|
||||||
|
/**
|
||||||
|
* 私钥路径或内容(用于签名)
|
||||||
|
* 优先级:content > location
|
||||||
|
*/
|
||||||
|
private String privateKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公钥路径或内容(用于验证)
|
||||||
|
* 优先级:content > location
|
||||||
|
*/
|
||||||
|
private String publicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密钥算法,默认 RSA
|
||||||
|
*/
|
||||||
|
private String algorithm = "RSA";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密钥长度,默认 2048
|
||||||
|
*/
|
||||||
|
private int keySize = 2048;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter 和 Setter(原有)
|
||||||
|
public String getHeader() { return header; }
|
||||||
|
public void setHeader(String header) { this.header = header; }
|
||||||
|
|
||||||
|
public String getPrefix() { return prefix; }
|
||||||
|
public void setPrefix(String prefix) { this.prefix = prefix; }
|
||||||
|
|
||||||
|
public Duration getExpiration() { return expiration; }
|
||||||
|
public void setExpiration(Duration expiration) { this.expiration = expiration; }
|
||||||
|
|
||||||
|
public Duration getRefreshExpiration() { return refreshExpiration; }
|
||||||
|
public void setRefreshExpiration(Duration refreshExpiration) { this.refreshExpiration = refreshExpiration; }
|
||||||
|
|
||||||
|
// RSA 配置 Getter 和 Setter
|
||||||
|
public RsaKey getRsa() { return rsa; }
|
||||||
|
public void setRsa(RsaKey rsa) { this.rsa = rsa; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码文本生成器
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class KaptchaTextCreator extends DefaultTextCreator
|
||||||
|
{
|
||||||
|
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText()
|
||||||
|
{
|
||||||
|
Integer result = 0;
|
||||||
|
Random random = new Random();
|
||||||
|
int x = random.nextInt(10);
|
||||||
|
int y = random.nextInt(10);
|
||||||
|
StringBuilder suChinese = new StringBuilder();
|
||||||
|
int randomoperands = random.nextInt(3);
|
||||||
|
if (randomoperands == 0)
|
||||||
|
{
|
||||||
|
result = x * y;
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
suChinese.append("*");
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
}
|
||||||
|
else if (randomoperands == 1)
|
||||||
|
{
|
||||||
|
if ((x != 0) && y % x == 0)
|
||||||
|
{
|
||||||
|
result = y / x;
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
suChinese.append("/");
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = x + y;
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
suChinese.append("+");
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (x >= y)
|
||||||
|
{
|
||||||
|
result = x - y;
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
suChinese.append("-");
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = y - x;
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
suChinese.append("-");
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
suChinese.append("=?@" + result);
|
||||||
|
return suChinese.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import org.lingniu.idp.enums.CustomScopes;
|
||||||
|
import org.lingniu.idp.model.dto.LoginUser;
|
||||||
|
import org.lingniu.idp.model.entity.SysUser;
|
||||||
|
import org.lingniu.idp.service.core.SysPermissionService;
|
||||||
|
import org.lingniu.idp.service.core.login.LoginService;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.StandardClaimNames;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationContext;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class OidcUserInfoMapper
|
||||||
|
implements Function<OidcUserInfoAuthenticationContext, OidcUserInfo> {
|
||||||
|
|
||||||
|
private final LoginService loginService;
|
||||||
|
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
private static final List<String> EMAIL_CLAIMS = Arrays.asList(
|
||||||
|
StandardClaimNames.EMAIL,
|
||||||
|
StandardClaimNames.EMAIL_VERIFIED
|
||||||
|
);
|
||||||
|
private static final List<String> PHONE_CLAIMS = Arrays.asList(
|
||||||
|
StandardClaimNames.PHONE_NUMBER,
|
||||||
|
StandardClaimNames.PHONE_NUMBER_VERIFIED
|
||||||
|
);
|
||||||
|
private static final List<String> PROFILE_CLAIMS = Arrays.asList(
|
||||||
|
StandardClaimNames.NAME,
|
||||||
|
StandardClaimNames.FAMILY_NAME,
|
||||||
|
StandardClaimNames.GIVEN_NAME,
|
||||||
|
StandardClaimNames.MIDDLE_NAME,
|
||||||
|
StandardClaimNames.NICKNAME,
|
||||||
|
StandardClaimNames.PREFERRED_USERNAME,
|
||||||
|
StandardClaimNames.PROFILE,
|
||||||
|
StandardClaimNames.PICTURE,
|
||||||
|
StandardClaimNames.WEBSITE,
|
||||||
|
StandardClaimNames.GENDER,
|
||||||
|
StandardClaimNames.BIRTHDATE,
|
||||||
|
StandardClaimNames.ZONEINFO,
|
||||||
|
StandardClaimNames.LOCALE,
|
||||||
|
StandardClaimNames.UPDATED_AT
|
||||||
|
);
|
||||||
|
|
||||||
|
public OidcUserInfoMapper(LoginService loginService) {this.loginService = loginService;}
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OidcUserInfo apply(OidcUserInfoAuthenticationContext authenticationContext) {
|
||||||
|
OAuth2Authorization authorization = authenticationContext.getAuthorization();
|
||||||
|
OidcIdToken idToken = authorization.getToken(OidcIdToken.class).getToken();
|
||||||
|
OAuth2AccessToken accessToken = authenticationContext.getAccessToken();
|
||||||
|
Map<String, Object> scopeRequestedClaims = getClaimsRequestedByScope(idToken.getClaims(),
|
||||||
|
accessToken.getScopes());
|
||||||
|
String userName = authorization.getPrincipalName();
|
||||||
|
SysUser sysUser = loginService.getUserDetail(userName);
|
||||||
|
scopeRequestedClaims.put("userId",sysUser.getUserId());
|
||||||
|
scopeRequestedClaims.put("currentDeptId",sysUser.getDeptId());
|
||||||
|
scopeRequestedClaims.put("username",sysUser.getUserName());
|
||||||
|
scopeRequestedClaims.put("userDepts",sysUser.getDeptList());
|
||||||
|
scopeRequestedClaims.put("userPosts",sysUser.getPosts());
|
||||||
|
scopeRequestedClaims.put("nickName",sysUser.getNickName());
|
||||||
|
scopeRequestedClaims.put("sex",sysUser.getSex());
|
||||||
|
if(accessToken.getScopes().contains(CustomScopes.PERMS.name().toLowerCase())){
|
||||||
|
Map<String, Object> permissionInfo = loginService.getPermissionInfo(sysUser);
|
||||||
|
scopeRequestedClaims.putAll(permissionInfo);
|
||||||
|
|
||||||
|
}
|
||||||
|
return new OidcUserInfo(scopeRequestedClaims);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> getClaimsRequestedByScope(Map<String, Object> claims,
|
||||||
|
Set<String> requestedScopes) {
|
||||||
|
Set<String> scopeRequestedClaimNames = new HashSet<>(32);
|
||||||
|
scopeRequestedClaimNames.add(StandardClaimNames.SUB);
|
||||||
|
|
||||||
|
if (requestedScopes.contains(OidcScopes.ADDRESS)) {
|
||||||
|
scopeRequestedClaimNames.add(StandardClaimNames.ADDRESS);
|
||||||
|
}
|
||||||
|
if (requestedScopes.contains(OidcScopes.EMAIL)) {
|
||||||
|
scopeRequestedClaimNames.addAll(EMAIL_CLAIMS);
|
||||||
|
}
|
||||||
|
if (requestedScopes.contains(OidcScopes.PHONE)) {
|
||||||
|
scopeRequestedClaimNames.addAll(PHONE_CLAIMS);
|
||||||
|
}
|
||||||
|
if (requestedScopes.contains(OidcScopes.PROFILE)) {
|
||||||
|
scopeRequestedClaimNames.addAll(PROFILE_CLAIMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, Object> requestedClaims = new HashMap<>(claims);
|
||||||
|
requestedClaims.keySet().removeIf((claimName) -> !scopeRequestedClaimNames.contains(claimName));
|
||||||
|
|
||||||
|
return requestedClaims;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取项目相关配置
|
||||||
|
*
|
||||||
|
* @author q
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "project")
|
||||||
|
public class ProjectConfig
|
||||||
|
{
|
||||||
|
/** 项目名称 */
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/** 版本 */
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
/** 版权年份 */
|
||||||
|
private String copyrightYear;
|
||||||
|
|
||||||
|
/** 上传路径 */
|
||||||
|
@Getter
|
||||||
|
private static String profile;
|
||||||
|
|
||||||
|
/** 获取地址开关 */
|
||||||
|
@Getter
|
||||||
|
private static boolean addressEnabled;
|
||||||
|
|
||||||
|
/** 验证码类型 */
|
||||||
|
@Getter
|
||||||
|
private static String captchaType;
|
||||||
|
|
||||||
|
public void setProfile(String profile)
|
||||||
|
{
|
||||||
|
ProjectConfig.profile = profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressEnabled(boolean addressEnabled)
|
||||||
|
{
|
||||||
|
ProjectConfig.addressEnabled = addressEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCaptchaType(String captchaType) {
|
||||||
|
ProjectConfig.captchaType = captchaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取导入上传路径
|
||||||
|
*/
|
||||||
|
public static String getImportPath()
|
||||||
|
{
|
||||||
|
return getProfile() + "/import";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取头像上传路径
|
||||||
|
*/
|
||||||
|
public static String getAvatarPath()
|
||||||
|
{
|
||||||
|
return getProfile() + "/avatar";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下载路径
|
||||||
|
*/
|
||||||
|
public static String getDownloadPath()
|
||||||
|
{
|
||||||
|
return getProfile() + "/download/";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取上传路径
|
||||||
|
*/
|
||||||
|
public static String getUploadPath()
|
||||||
|
{
|
||||||
|
return getProfile() + "/upload";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import org.lingniu.idp.config.serializer.FastJson2JsonRedisSerializer;
|
||||||
|
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis配置
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
|
public class RedisConfig extends CachingConfigurerSupport
|
||||||
|
{
|
||||||
|
@Bean
|
||||||
|
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||||
|
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
|
||||||
|
{
|
||||||
|
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||||
|
template.setConnectionFactory(connectionFactory);
|
||||||
|
|
||||||
|
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
|
||||||
|
|
||||||
|
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||||
|
template.setKeySerializer(new StringRedisSerializer());
|
||||||
|
template.setValueSerializer(serializer);
|
||||||
|
|
||||||
|
// Hash的key也采用StringRedisSerializer的序列化方式
|
||||||
|
template.setHashKeySerializer(new StringRedisSerializer());
|
||||||
|
template.setHashValueSerializer(serializer);
|
||||||
|
|
||||||
|
template.afterPropertiesSet();
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DefaultRedisScript<Long> limitScript()
|
||||||
|
{
|
||||||
|
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
|
||||||
|
redisScript.setScriptText(limitScriptText());
|
||||||
|
redisScript.setResultType(Long.class);
|
||||||
|
return redisScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流脚本
|
||||||
|
*/
|
||||||
|
private String limitScriptText()
|
||||||
|
{
|
||||||
|
return "local key = KEYS[1]\n" +
|
||||||
|
"local count = tonumber(ARGV[1])\n" +
|
||||||
|
"local time = tonumber(ARGV[2])\n" +
|
||||||
|
"local current = redis.call('get', key);\n" +
|
||||||
|
"if current and tonumber(current) > count then\n" +
|
||||||
|
" return tonumber(current);\n" +
|
||||||
|
"end\n" +
|
||||||
|
"current = redis.call('incr', key)\n" +
|
||||||
|
"if tonumber(current) == 1 then\n" +
|
||||||
|
" redis.call('expire', key, time)\n" +
|
||||||
|
"end\n" +
|
||||||
|
"return tonumber(current);";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import org.lingniu.idp.security.filter.login.MobilePasswordAuthenticationFilter;
|
||||||
|
import org.lingniu.idp.security.handler.AuthenticationEntryPointImpl;
|
||||||
|
import org.lingniu.idp.security.handler.LoginSuccessHandler;
|
||||||
|
import org.lingniu.idp.security.handler.LogoutSuccessHandlerImpl;
|
||||||
|
import org.lingniu.idp.security.provider.MobilePasswordAuthenticationProvider;
|
||||||
|
import org.lingniu.idp.security.provider.SmsCodeAuthenticationProvider;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||||
|
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
//@EnableWebSecurity
|
||||||
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final AuthenticationEntryPointImpl unauthorizedHandler;
|
||||||
|
private final LogoutSuccessHandlerImpl logoutSuccessHandler;
|
||||||
|
private final MobilePasswordAuthenticationProvider mobilePasswordAuthenticationProvider;
|
||||||
|
private final SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;
|
||||||
|
private final LoginSuccessHandler successHandler;
|
||||||
|
|
||||||
|
public SecurityConfig(AuthenticationEntryPointImpl unauthorizedHandler, LogoutSuccessHandlerImpl logoutSuccessHandler, MobilePasswordAuthenticationProvider mobilePasswordAuthenticationProvider, SmsCodeAuthenticationProvider smsCodeAuthenticationProvider, LoginSuccessHandler successHandler) {
|
||||||
|
this.unauthorizedHandler = unauthorizedHandler;
|
||||||
|
this.logoutSuccessHandler = logoutSuccessHandler;
|
||||||
|
this.mobilePasswordAuthenticationProvider = mobilePasswordAuthenticationProvider;
|
||||||
|
this.smsCodeAuthenticationProvider = smsCodeAuthenticationProvider;
|
||||||
|
this.successHandler = successHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(2)
|
||||||
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
|
// 禁用HTTP响应标头
|
||||||
|
.headers((headersCustomizer) -> {
|
||||||
|
headersCustomizer.cacheControl(HeadersConfigurer.CacheControlConfig::disable).frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin);
|
||||||
|
})
|
||||||
|
// 认证失败处理类
|
||||||
|
.exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
|
||||||
|
// 基于token,所以不需要session
|
||||||
|
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
|
.authorizeHttpRequests(authorize -> authorize
|
||||||
|
.requestMatchers(
|
||||||
|
"/api/login/**",
|
||||||
|
"/captcha/image"
|
||||||
|
).permitAll()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
)
|
||||||
|
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
|
||||||
|
// 添加Logout filter
|
||||||
|
.logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
|
||||||
|
.rememberMe(remember -> remember
|
||||||
|
.tokenValiditySeconds(7 * 24 * 60 * 60) // 7天
|
||||||
|
.key("remember-me-idp")
|
||||||
|
);
|
||||||
|
addFilters(http);
|
||||||
|
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
private void addFilters(HttpSecurity http){
|
||||||
|
MobilePasswordAuthenticationFilter mobilePasswordAuthenticationFilter = new MobilePasswordAuthenticationFilter(authenticationManager());
|
||||||
|
mobilePasswordAuthenticationFilter.setAuthenticationSuccessHandler(successHandler);
|
||||||
|
http.addFilterBefore(mobilePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 自定义JWT认证转换器
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public JwtAuthenticationConverter jwtAuthenticationConverter() {
|
||||||
|
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
|
||||||
|
grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
|
||||||
|
grantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
|
||||||
|
|
||||||
|
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
|
||||||
|
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
|
||||||
|
|
||||||
|
return jwtAuthenticationConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager() {
|
||||||
|
List<AuthenticationProvider> providers = Arrays.asList(
|
||||||
|
mobilePasswordAuthenticationProvider,
|
||||||
|
smsCodeAuthenticationProvider
|
||||||
|
);
|
||||||
|
|
||||||
|
return new ProviderManager(providers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
|
||||||
|
String portal = bCryptPasswordEncoder.encode("portal");
|
||||||
|
System.out.println(portal);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||||
|
import org.lingniu.idp.utils.Threads;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程池配置
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
**/
|
||||||
|
@Configuration
|
||||||
|
public class ThreadPoolConfig
|
||||||
|
{
|
||||||
|
// 核心线程池大小
|
||||||
|
private int corePoolSize = 50;
|
||||||
|
|
||||||
|
// 最大可创建的线程数
|
||||||
|
private int maxPoolSize = 200;
|
||||||
|
|
||||||
|
// 队列最大长度
|
||||||
|
private int queueCapacity = 1000;
|
||||||
|
|
||||||
|
// 线程池维护线程所允许的空闲时间
|
||||||
|
private int keepAliveSeconds = 300;
|
||||||
|
|
||||||
|
@Bean(name = "threadPoolTaskExecutor")
|
||||||
|
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
|
||||||
|
{
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setMaxPoolSize(maxPoolSize);
|
||||||
|
executor.setCorePoolSize(corePoolSize);
|
||||||
|
executor.setQueueCapacity(queueCapacity);
|
||||||
|
executor.setKeepAliveSeconds(keepAliveSeconds);
|
||||||
|
// 线程池对拒绝任务(无线程可用)的处理策略
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行周期性或定时任务
|
||||||
|
*/
|
||||||
|
@Bean(name = "scheduledExecutorService")
|
||||||
|
protected ScheduledExecutorService scheduledExecutorService()
|
||||||
|
{
|
||||||
|
return new ScheduledThreadPoolExecutor(corePoolSize,
|
||||||
|
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
|
||||||
|
new ThreadPoolExecutor.CallerRunsPolicy())
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void afterExecute(Runnable r, Throwable t)
|
||||||
|
{
|
||||||
|
super.afterExecute(r, t);
|
||||||
|
Threads.printException(r, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020-2025 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.lingniu.idp.config;
|
||||||
|
|
||||||
|
import org.apache.catalina.connector.Connector;
|
||||||
|
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||||
|
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Profile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Joe Grandja
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
@Profile("!test") // Exclude this from DemoAuthorizationServerApplicationTests and DemoAuthorizationServerConsentTests
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
public class TomcatServerConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> connectorCustomizer() {
|
||||||
|
return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createHttpConnector());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Connector createHttpConnector() {
|
||||||
|
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
|
||||||
|
connector.setScheme("http");
|
||||||
|
connector.setPort(8000);
|
||||||
|
connector.setSecure(false);
|
||||||
|
connector.setRedirectPort(8443);
|
||||||
|
return connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package org.lingniu.idp.config.serializer;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONReader;
|
||||||
|
import com.alibaba.fastjson2.JSONWriter;
|
||||||
|
import com.alibaba.fastjson2.filter.Filter;
|
||||||
|
import org.lingniu.idp.constant.Constants;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.SerializationException;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis使用FastJson序列化
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
|
||||||
|
{
|
||||||
|
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||||
|
|
||||||
|
static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);
|
||||||
|
|
||||||
|
private Class<T> clazz;
|
||||||
|
|
||||||
|
public FastJson2JsonRedisSerializer(Class<T> clazz)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.clazz = clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serialize(T t) throws SerializationException
|
||||||
|
{
|
||||||
|
if (t == null)
|
||||||
|
{
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T deserialize(byte[] bytes) throws SerializationException
|
||||||
|
{
|
||||||
|
if (bytes == null || bytes.length <= 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String str = new String(bytes, DEFAULT_CHARSET);
|
||||||
|
|
||||||
|
return JSON.parseObject(str, clazz, AUTO_TYPE_FILTER);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package org.lingniu.idp.config.serializer;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.databind.BeanProperty;
|
||||||
|
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
|
||||||
|
import org.lingniu.idp.annotation.Sensitive;
|
||||||
|
import org.lingniu.idp.model.dto.LoginUser;
|
||||||
|
import org.lingniu.idp.enums.DesensitizedType;
|
||||||
|
import org.lingniu.idp.utils.SecurityUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据脱敏序列化过滤
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer
|
||||||
|
{
|
||||||
|
private DesensitizedType desensitizedType;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException
|
||||||
|
{
|
||||||
|
if (desensitization())
|
||||||
|
{
|
||||||
|
gen.writeString(desensitizedType.desensitizer().apply(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gen.writeString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
|
||||||
|
throws JsonMappingException
|
||||||
|
{
|
||||||
|
Sensitive annotation = property.getAnnotation(Sensitive.class);
|
||||||
|
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
|
||||||
|
{
|
||||||
|
this.desensitizedType = annotation.desensitizedType();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return prov.findValueSerializer(property.getType(), property);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需要脱敏处理
|
||||||
|
*/
|
||||||
|
private boolean desensitization()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LoginUser securityUser = SecurityUtils.getLoginUser();
|
||||||
|
// 管理员不脱敏
|
||||||
|
return !securityUser.getUser().isAdmin();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package org.lingniu.idp.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存的key 常量
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CacheConstants
|
||||||
|
{
|
||||||
|
public static final String prefix = "idp_";
|
||||||
|
/**
|
||||||
|
* 登录用户 redis key
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_TOKEN_KEY = prefix + "login_tokens:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码 redis key
|
||||||
|
*/
|
||||||
|
public static final String CAPTCHA_CODE_KEY = prefix + "captcha_codes:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数管理 cache key
|
||||||
|
*/
|
||||||
|
public static final String SYS_CONFIG_KEY = prefix + "sys_config:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典管理 cache key
|
||||||
|
*/
|
||||||
|
public static final String SYS_DICT_KEY = prefix + "sys_dict:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 防重提交 redis key
|
||||||
|
*/
|
||||||
|
public static final String REPEAT_SUBMIT_KEY = prefix + "repeat_submit:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流 redis key
|
||||||
|
*/
|
||||||
|
public static final String RATE_LIMIT_KEY = prefix + "rate_limit:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录账户密码错误次数 redis key
|
||||||
|
*/
|
||||||
|
public static final String PWD_ERR_CNT_KEY = prefix + "pwd_err_cnt:";
|
||||||
|
|
||||||
|
// Access Token存储: String结构
|
||||||
|
// 格式: access_token:{token}
|
||||||
|
public static final String ACCESS_TOKEN_KEY = prefix + "access_token:%s";
|
||||||
|
|
||||||
|
// Refresh Token存储: Hash结构
|
||||||
|
// 格式: refresh_token:{token}
|
||||||
|
public static final String REFRESH_TOKEN_KEY = prefix + "refresh_token:%s";
|
||||||
|
|
||||||
|
// 用户会话管理
|
||||||
|
public static final String USER_SESSIONS = prefix + "user_sessions:%s"; // userId -> session列表
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package org.lingniu.idp.constant;
|
||||||
|
|
||||||
|
import com.nimbusds.openid.connect.sdk.claims.ClaimType;
|
||||||
|
import com.nimbusds.openid.connect.sdk.claims.CommonClaimsSet;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用常量信息
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class Constants
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* UTF-8 字符集
|
||||||
|
*/
|
||||||
|
public static final String UTF8 = "UTF-8";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GBK 字符集
|
||||||
|
*/
|
||||||
|
public static final String GBK = "GBK";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统语言
|
||||||
|
*/
|
||||||
|
public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* www主域
|
||||||
|
*/
|
||||||
|
public static final String WWW = "www.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http请求
|
||||||
|
*/
|
||||||
|
public static final String HTTP = "http://";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https请求
|
||||||
|
*/
|
||||||
|
public static final String HTTPS = "https://";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用成功标识
|
||||||
|
*/
|
||||||
|
public static final String SUCCESS = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用失败标识
|
||||||
|
*/
|
||||||
|
public static final String FAIL = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录成功
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_SUCCESS = "Success";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注销
|
||||||
|
*/
|
||||||
|
public static final String LOGOUT = "Logout";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*/
|
||||||
|
public static final String REGISTER = "Register";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录失败
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_FAIL = "Error";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有权限标识
|
||||||
|
*/
|
||||||
|
public static final String ALL_PERMISSION = "*:*:*";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员角色权限标识
|
||||||
|
*/
|
||||||
|
public static final String SUPER_ADMIN = "admin";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色权限分隔符
|
||||||
|
*/
|
||||||
|
public static final String ROLE_DELIMITER = ",";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限标识分隔符
|
||||||
|
*/
|
||||||
|
public static final String PERMISSION_DELIMITER = ",";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码有效期(分钟)
|
||||||
|
*/
|
||||||
|
public static final Integer CAPTCHA_EXPIRATION = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌
|
||||||
|
*/
|
||||||
|
public static final String TOKEN = "token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌前缀
|
||||||
|
*/
|
||||||
|
public static final String TOKEN_PREFIX = "Bearer ";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌前缀
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_USER_KEY = "login_user_key";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
public static final String JWT_USERID = "userid";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名称
|
||||||
|
*/
|
||||||
|
public static final String JWT_USERNAME = CommonClaimsSet.SUB_CLAIM_NAME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户头像
|
||||||
|
*/
|
||||||
|
public static final String JWT_AVATAR = "avatar";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
public static final String JWT_CREATED = "created";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户权限
|
||||||
|
*/
|
||||||
|
public static final String JWT_AUTHORITIES = "authorities";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源映射路径 前缀
|
||||||
|
*/
|
||||||
|
public static final String RESOURCE_PREFIX = "/profile";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RMI 远程方法调用
|
||||||
|
*/
|
||||||
|
public static final String LOOKUP_RMI = "rmi:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAP 远程方法调用
|
||||||
|
*/
|
||||||
|
public static final String LOOKUP_LDAP = "ldap:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAPS 远程方法调用
|
||||||
|
*/
|
||||||
|
public static final String LOOKUP_LDAPS = "ldaps:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
|
||||||
|
*/
|
||||||
|
public static final String[] JSON_WHITELIST_STR = { "com.portal" };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
|
||||||
|
*/
|
||||||
|
public static final String[] JOB_WHITELIST_STR = { "com.portal.quartz.task" };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务违规的字符
|
||||||
|
*/
|
||||||
|
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
|
||||||
|
"org.springframework", "org.apache", "org.lingniu.idp.utils.file", "org.lingniu.idp.config", "com.portal.generator" };
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package org.lingniu.idp.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户常量信息
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class UserConstants
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 平台内系统用户的唯一标志
|
||||||
|
*/
|
||||||
|
public static final String SYS_USER = "SYS_USER";
|
||||||
|
|
||||||
|
/** 正常状态 */
|
||||||
|
public static final String NORMAL = "0";
|
||||||
|
|
||||||
|
/** 异常状态 */
|
||||||
|
public static final String EXCEPTION = "1";
|
||||||
|
|
||||||
|
/** 用户封禁状态 */
|
||||||
|
public static final String USER_DISABLE = "1";
|
||||||
|
|
||||||
|
/** 角色正常状态 */
|
||||||
|
public static final String ROLE_NORMAL = "0";
|
||||||
|
|
||||||
|
/** 角色封禁状态 */
|
||||||
|
public static final String ROLE_DISABLE = "1";
|
||||||
|
|
||||||
|
/** 部门正常状态 */
|
||||||
|
public static final String DEPT_NORMAL = "0";
|
||||||
|
|
||||||
|
/** 部门停用状态 */
|
||||||
|
public static final String DEPT_DISABLE = "1";
|
||||||
|
|
||||||
|
/** 字典正常状态 */
|
||||||
|
public static final String DICT_NORMAL = "0";
|
||||||
|
|
||||||
|
/** 是否为系统默认(是) */
|
||||||
|
public static final String YES = "Y";
|
||||||
|
|
||||||
|
/** 是否菜单外链(是) */
|
||||||
|
public static final String YES_FRAME = "0";
|
||||||
|
|
||||||
|
/** 是否菜单外链(否) */
|
||||||
|
public static final String NO_FRAME = "1";
|
||||||
|
|
||||||
|
/** 菜单类型(目录) */
|
||||||
|
public static final String TYPE_DIR = "M";
|
||||||
|
|
||||||
|
/** 菜单类型(菜单) */
|
||||||
|
public static final String TYPE_MENU = "C";
|
||||||
|
|
||||||
|
/** 菜单类型(按钮) */
|
||||||
|
public static final String TYPE_BUTTON = "F";
|
||||||
|
|
||||||
|
/** Layout组件标识 */
|
||||||
|
public final static String LAYOUT = "Layout";
|
||||||
|
|
||||||
|
/** ParentView组件标识 */
|
||||||
|
public final static String PARENT_VIEW = "ParentView";
|
||||||
|
|
||||||
|
/** InnerLink组件标识 */
|
||||||
|
public final static String INNER_LINK = "InnerLink";
|
||||||
|
|
||||||
|
/** 校验是否唯一的返回标识 */
|
||||||
|
public final static boolean UNIQUE = true;
|
||||||
|
public final static boolean NOT_UNIQUE = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名长度限制
|
||||||
|
*/
|
||||||
|
public static final int USERNAME_MIN_LENGTH = 2;
|
||||||
|
public static final int USERNAME_MAX_LENGTH = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码长度限制
|
||||||
|
*/
|
||||||
|
public static final int PASSWORD_MIN_LENGTH = 5;
|
||||||
|
public static final int PASSWORD_MAX_LENGTH = 20;
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package org.lingniu.idp.controller;
|
||||||
|
|
||||||
|
import com.google.code.kaptcha.Producer;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.lingniu.idp.config.ProjectConfig;
|
||||||
|
import org.lingniu.idp.constant.CacheConstants;
|
||||||
|
import org.lingniu.idp.constant.Constants;
|
||||||
|
import org.lingniu.idp.model.base.AjaxResult;
|
||||||
|
import org.lingniu.idp.common.redis.RedisCache;
|
||||||
|
import org.lingniu.idp.utils.sign.Base64;
|
||||||
|
import org.lingniu.idp.utils.uuid.IdUtils;
|
||||||
|
import org.lingniu.idp.service.ISysConfigService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.util.FastByteArrayOutputStream;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码操作处理
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/captcha")
|
||||||
|
public class CaptchaController
|
||||||
|
{
|
||||||
|
@Resource(name = "captchaProducer")
|
||||||
|
private Producer captchaProducer;
|
||||||
|
|
||||||
|
@Resource(name = "captchaProducerMath")
|
||||||
|
private Producer captchaProducerMath;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisCache redisCache;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysConfigService configService;
|
||||||
|
/**
|
||||||
|
* 生成验证码
|
||||||
|
*/
|
||||||
|
@GetMapping("/image")
|
||||||
|
public AjaxResult getCode(HttpServletResponse response) throws IOException
|
||||||
|
{
|
||||||
|
AjaxResult ajax = AjaxResult.success();
|
||||||
|
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
||||||
|
ajax.put("captchaEnabled", captchaEnabled);
|
||||||
|
if (!captchaEnabled)
|
||||||
|
{
|
||||||
|
return ajax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存验证码信息
|
||||||
|
String uuid = IdUtils.simpleUUID();
|
||||||
|
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
|
||||||
|
|
||||||
|
String capStr = null, code = null;
|
||||||
|
BufferedImage image = null;
|
||||||
|
|
||||||
|
// 生成验证码
|
||||||
|
String captchaType = ProjectConfig.getCaptchaType();
|
||||||
|
if ("math".equals(captchaType))
|
||||||
|
{
|
||||||
|
String capText = captchaProducerMath.createText();
|
||||||
|
capStr = capText.substring(0, capText.lastIndexOf("@"));
|
||||||
|
code = capText.substring(capText.lastIndexOf("@") + 1);
|
||||||
|
image = captchaProducerMath.createImage(capStr);
|
||||||
|
}
|
||||||
|
else if ("char".equals(captchaType))
|
||||||
|
{
|
||||||
|
capStr = code = captchaProducer.createText();
|
||||||
|
image = captchaProducer.createImage(capStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||||
|
// 转换流信息写出
|
||||||
|
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ImageIO.write(image, "jpg", os);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
return AjaxResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
ajax.put("uuid", uuid);
|
||||||
|
ajax.put("img", Base64.encode(os.toByteArray()));
|
||||||
|
return ajax;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.lingniu.idp.controller;
|
||||||
|
|
||||||
|
import org.lingniu.idp.model.base.AjaxResult;
|
||||||
|
import org.lingniu.idp.model.entity.SysMenu;
|
||||||
|
import org.lingniu.idp.model.entity.SysUser;
|
||||||
|
import org.lingniu.idp.service.ISysMenuService;
|
||||||
|
import org.lingniu.idp.service.ISysUserService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录验证
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/idp")
|
||||||
|
public class SysLoginController
|
||||||
|
{
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysUserService sysUserService;
|
||||||
|
@Autowired
|
||||||
|
private ISysMenuService menuService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取路由信息
|
||||||
|
*
|
||||||
|
* @return 路由信息
|
||||||
|
*/
|
||||||
|
@GetMapping("getRouters")
|
||||||
|
public AjaxResult getRouters(@AuthenticationPrincipal Jwt jwt)
|
||||||
|
{
|
||||||
|
SysUser sysUser = sysUserService.selectUserByUserName(jwt.getSubject());
|
||||||
|
List<SysMenu> menus = menuService.selectMenuTreeByUserId(sysUser.getUserId());
|
||||||
|
return AjaxResult.success(menuService.buildMenus(menus));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
### 验证码
|
||||||
|
# @no-redirect
|
||||||
|
GET http://localhost:8000/captcha/image
|
||||||
|
|
||||||
|
### 密码登录 054aae95108e409dadc12af52f556a70
|
||||||
|
# @no-redirect
|
||||||
|
POST http://localhost:8000/api/login/account
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
username=admin&password=admin123&uuid=1316459cfa7f40429bdc0f751229eb23&code=2
|
||||||
|
|
||||||
|
|
||||||
|
##### e040b13e72e84086b63da369d60887e4
|
||||||
|
POST http://localhost:8000/oauth2/authorize
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
Accept: application/json
|
||||||
|
Idp: 53c55ddb3caf44568ba429347fdad0e6
|
||||||
|
Cookie: idp_refresh_token=7bb21a0dcac94aec99f08ae6a2d6db30
|
||||||
|
|
||||||
|
client_id=2c6f1d9ff78641c78d72a848&redirect_uri=http%3A%2F%2Flocalhost%3A81%2Fcallback&response_type=code&state=LXcbn1xobq6unvUCz5uwG7PcwtsNdbWg&scope=openid
|
||||||
|
|
||||||
|
### @name 一次性授权码登录
|
||||||
|
POST http://localhost:8000/oauth2/token
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
Authorization: Basic MmM2ZjFkOWZmNzg2NDFjNzhkNzJhODQ4OmkxYnBlcjFKdzJnTGVUelVOMW9uaXd1SUNQRFFnTnVRRWNZeFRLSjVpdjA=
|
||||||
|
|
||||||
|
grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A81%2Fcallback&code=qmkNPAOk7pKTrTcHecwfSuona-O9Kjs-bbgSthovqSZz-wBhrqh9SUVeVUEN8ct4Gr7V-Dt4xMeupw3gFslSlbxZ8t2UHl74-63rGp7xnDVUGFWAA99TVa8hOnSgABZX&state=LXcbn1xobq6unvUCz5uwG7PcwtsNdbWg
|
||||||
|
|
||||||
|
|
||||||
|
####
|
||||||
|
GET http://localhost:8000/account/getInfo
|
||||||
|
Authorization: Bearer eyJraWQiOiJpZHAiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6IjJjNmYxZDlmZjc4NjQxYzc4ZDcyYTg0OCIsIm5iZiI6MTc3MDI1NTA3MiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDAwIiwiZXhwIjoxNzcwMjU4NjcyLCJpYXQiOjE3NzAyNTUwNzIsImp0aSI6IjVmNzAxM2EwLTU0MjctNDMyOC04ZTg0LWUwZjE0YjA4Y2IyYSJ9.KbradWCC1p6mD-JEd3IefUuzNvpNyUvGwyfuTRBVCC7jh-QGU36j4WxkeCtNJqaCBWZWQZVCJj068ysqanbRZRiSA4nADFMZnRVdBJD340TknKcGp7PbmiJfPD_uh4OzLosAu9xEUPjEW6q6rrjEqtIA9brK8NfP6A8A7aB8fYyKE0V1VO6j06AwC1CmXxUGrDgtJpU9_4NhV1Jf4cLBtECVG0pQDWMrEUNtrShPoa8gNJUUhP0gU0g-PyqBwlRhVl7Ra6T5lr4IIlsgK2D0Zu0ssFSJjZv_zhTW5Lo3xbe_DKVbWV4buJvLrHzlGBdFn7IV1-x6FwSZX10FBvXtOA
|
||||||
|
###
|
||||||
|
GET http://localhost:8000/.well-known/openid-configuration
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
GET http://localhost:8000/userinfo
|
||||||
|
Authorization: Bearer eyJraWQiOiJpZHAiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6IjJjNmYxZDlmZjc4NjQxYzc4ZDcyYTg0OCIsIm5iZiI6MTc3MDM2NTc1Nywic2NvcGUiOlsib3BlbmlkIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMCIsImV4cCI6MTc3MDQwODk1NywiaWF0IjoxNzcwMzY1NzU3LCJqdGkiOiIwOWFjNDJjZi1jNmI4LTQ4MDMtOTkyMi0yMTYwMTk0Zjg1MzQifQ.TIrICdQ2iltZXS7PAGc1MHi_cHS9VuWgYsRZGI5t-ZoPjP1fvnkDg4OwO4In7vl1617-bUSlvl42Dm4AVZvtsnNWVVg6LXyf-Cge1kPENynnrpJzPRHkT5XwHno552UWwS6B3VtlSXsHnlK7D5BEZmsw4X5bL0fF56IPjoiaYjhgPoEp_Q9kU7b6d_2gnQAQeOst-K0yFtYtBIWl6QJX9q9Q-4maJdbuOAWqUOySTg2STKII3XYqK-r8sor4cv55itFqX4VZuhQuSQwbumLyJq55YYtl-vzYvST9zHRyeYxWaHVIhDZRNZR_AYkVB-Oj_8lASWRpDOSI10LJr4M1Qw
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
POST http://localhost:8000/oauth2/token
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
Authorization: Basic MmM2ZjFkOWZmNzg2NDFjNzhkNzJhODQ4OmkxYnBlcjFKdzJnTGVUelVOMW9uaXd1SUNQRFFnTnVRRWNZeFRLSjVpdjA=
|
||||||
|
|
||||||
|
grant_type=refresh_token&refresh_token=_NfU5Gdy_dANJkbvjJm6cK7PxNSHyQexWMY5KthA8Hs_nOFtPnTVChsHF-dmLjzhDRZk5nHNZWV7XhxyOp5qS-nLjScsrbvVwSmZhb20QpDLaSoUGtF-ZdBawvlceXks
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作状态
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum BusinessStatus
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 成功
|
||||||
|
*/
|
||||||
|
SUCCESS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败
|
||||||
|
*/
|
||||||
|
FAIL,
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务操作类型
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public enum BusinessType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 其它
|
||||||
|
*/
|
||||||
|
OTHER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
*/
|
||||||
|
INSERT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改
|
||||||
|
*/
|
||||||
|
UPDATE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
DELETE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权
|
||||||
|
*/
|
||||||
|
GRANT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出
|
||||||
|
*/
|
||||||
|
EXPORT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入
|
||||||
|
*/
|
||||||
|
IMPORT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强退
|
||||||
|
*/
|
||||||
|
FORCE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成代码
|
||||||
|
*/
|
||||||
|
GENCODE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空数据
|
||||||
|
*/
|
||||||
|
CLEAN,
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
public enum CustomScopes {
|
||||||
|
PERMS
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限
|
||||||
|
*/
|
||||||
|
public enum DataScope {
|
||||||
|
ALL(1),
|
||||||
|
CUSTOM(2),
|
||||||
|
DEPT_AND_SUB(3),
|
||||||
|
DEPT_SELF(4),
|
||||||
|
USER_SELF(5);
|
||||||
|
private Integer value;
|
||||||
|
DataScope(Integer value){
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int value(){
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Integer value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据源
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public enum DataSourceType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 主库
|
||||||
|
*/
|
||||||
|
MASTER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从库
|
||||||
|
*/
|
||||||
|
SLAVE
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
import org.lingniu.idp.utils.DesensitizedUtil;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脱敏类型
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public enum DesensitizedType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 姓名,第2位星号替换
|
||||||
|
*/
|
||||||
|
USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码,全部字符都用*代替
|
||||||
|
*/
|
||||||
|
PASSWORD(DesensitizedUtil::password),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份证,中间10位星号替换
|
||||||
|
*/
|
||||||
|
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机号,中间4位星号替换
|
||||||
|
*/
|
||||||
|
PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换
|
||||||
|
*/
|
||||||
|
EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行卡号,保留最后4位,其他星号替换
|
||||||
|
*/
|
||||||
|
BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车牌号码,包含普通车辆、新能源车辆
|
||||||
|
*/
|
||||||
|
CAR_LICENSE(DesensitizedUtil::carLicense);
|
||||||
|
|
||||||
|
private final Function<String, String> desensitizer;
|
||||||
|
|
||||||
|
DesensitizedType(Function<String, String> desensitizer)
|
||||||
|
{
|
||||||
|
this.desensitizer = desensitizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<String, String> desensitizer()
|
||||||
|
{
|
||||||
|
return desensitizer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备类型枚举
|
||||||
|
*/
|
||||||
|
public enum DeviceType {
|
||||||
|
WEB("网页"),
|
||||||
|
IOS("iOS"),
|
||||||
|
ANDROID("安卓"),
|
||||||
|
H5("H5"),
|
||||||
|
MINI_PROGRAM("小程序"),
|
||||||
|
DESKTOP("桌面端"),
|
||||||
|
OTHER("其他");
|
||||||
|
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
DeviceType(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求方式
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public enum HttpMethod
|
||||||
|
{
|
||||||
|
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
|
||||||
|
|
||||||
|
private static final Map<String, HttpMethod> mappings = new HashMap<>(16);
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
for (HttpMethod httpMethod : values())
|
||||||
|
{
|
||||||
|
mappings.put(httpMethod.name(), httpMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static HttpMethod resolve(@Nullable String method)
|
||||||
|
{
|
||||||
|
return (method != null ? mappings.get(method) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(String method)
|
||||||
|
{
|
||||||
|
return (this == resolve(method));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流类型
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum LimitType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 默认策略全局限流
|
||||||
|
*/
|
||||||
|
DEFAULT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据请求者IP进行限流
|
||||||
|
*/
|
||||||
|
IP
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作人类别
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public enum OperatorType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 其它
|
||||||
|
*/
|
||||||
|
OTHER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台用户
|
||||||
|
*/
|
||||||
|
MANAGE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机端用户
|
||||||
|
*/
|
||||||
|
MOBILE
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤销原因枚举
|
||||||
|
*/
|
||||||
|
public enum RevokeReason {
|
||||||
|
USER_LOGOUT("用户主动登出"),
|
||||||
|
ADMIN_REVOKED("管理员撤销"),
|
||||||
|
DEVICE_CHANGED("设备变更"),
|
||||||
|
SUSPICIOUS_ACTIVITY("可疑活动"),
|
||||||
|
PASSWORD_CHANGED("密码修改"),
|
||||||
|
SESSION_EXPIRED("会话过期"),
|
||||||
|
SECURITY_POLICY("安全策略"),
|
||||||
|
OTHER("其他");
|
||||||
|
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
RevokeReason(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.lingniu.idp.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户状态
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public enum UserStatus
|
||||||
|
{
|
||||||
|
OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
UserStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.lingniu.idp.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 演示模式异常
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class DemoModeException extends RuntimeException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public DemoModeException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package org.lingniu.idp.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class GlobalException extends RuntimeException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误提示
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误明细,内部调试错误
|
||||||
|
*
|
||||||
|
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
|
||||||
|
*/
|
||||||
|
private String detailMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空构造方法,避免反序列化问题
|
||||||
|
*/
|
||||||
|
public GlobalException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalException(String message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetailMessage()
|
||||||
|
{
|
||||||
|
return detailMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalException setDetailMessage(String detailMessage)
|
||||||
|
{
|
||||||
|
this.detailMessage = detailMessage;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage()
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalException setMessage(String message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package org.lingniu.idp.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务异常
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public final class ServiceException extends RuntimeException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*/
|
||||||
|
private Integer code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误提示
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误明细,内部调试错误
|
||||||
|
*
|
||||||
|
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
|
||||||
|
*/
|
||||||
|
private String detailMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空构造方法,避免反序列化问题
|
||||||
|
*/
|
||||||
|
public ServiceException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException(String message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException(String message, Integer code)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetailMessage()
|
||||||
|
{
|
||||||
|
return detailMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage()
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException setMessage(String message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException setDetailMessage(String detailMessage)
|
||||||
|
{
|
||||||
|
this.detailMessage = detailMessage;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.lingniu.idp.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具类异常
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class UtilException extends RuntimeException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 8247610319171014183L;
|
||||||
|
|
||||||
|
public UtilException(Throwable e)
|
||||||
|
{
|
||||||
|
super(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UtilException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UtilException(String message, Throwable throwable)
|
||||||
|
{
|
||||||
|
super(message, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package org.lingniu.idp.exception.base;
|
||||||
|
|
||||||
|
import org.lingniu.idp.utils.MessageUtils;
|
||||||
|
import org.lingniu.idp.utils.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础异常
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class BaseException extends RuntimeException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属模块
|
||||||
|
*/
|
||||||
|
private String module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码对应的参数
|
||||||
|
*/
|
||||||
|
private Object[] args;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误消息
|
||||||
|
*/
|
||||||
|
private String defaultMessage;
|
||||||
|
|
||||||
|
public BaseException(String module, String code, Object[] args, String defaultMessage)
|
||||||
|
{
|
||||||
|
this.module = module;
|
||||||
|
this.code = code;
|
||||||
|
this.args = args;
|
||||||
|
this.defaultMessage = defaultMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseException(String module, String code, Object[] args)
|
||||||
|
{
|
||||||
|
this(module, code, args, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseException(String module, String defaultMessage)
|
||||||
|
{
|
||||||
|
this(module, null, null, defaultMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseException(String code, Object[] args)
|
||||||
|
{
|
||||||
|
this(null, code, args, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseException(String defaultMessage)
|
||||||
|
{
|
||||||
|
this(null, null, null, defaultMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage()
|
||||||
|
{
|
||||||
|
String message = null;
|
||||||
|
if (!StringUtils.isEmpty(code))
|
||||||
|
{
|
||||||
|
message = MessageUtils.message(code, args);
|
||||||
|
}
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
message = defaultMessage;
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModule()
|
||||||
|
{
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getArgs()
|
||||||
|
{
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDefaultMessage()
|
||||||
|
{
|
||||||
|
return defaultMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.lingniu.idp.exception.user;
|
||||||
|
|
||||||
|
import org.lingniu.idp.exception.user.UserException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 黑名单IP异常类
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class BlackListException extends UserException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public BlackListException()
|
||||||
|
{
|
||||||
|
super("login.blocked", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.lingniu.idp.exception.user;
|
||||||
|
|
||||||
|
import org.lingniu.idp.exception.user.UserException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码错误异常类
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class CaptchaException extends UserException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public CaptchaException()
|
||||||
|
{
|
||||||
|
super("user.jcaptcha.error", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.lingniu.idp.exception.user;
|
||||||
|
|
||||||
|
import org.lingniu.idp.exception.user.UserException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码失效异常类
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class CaptchaExpireException extends UserException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public CaptchaExpireException()
|
||||||
|
{
|
||||||
|
super("user.jcaptcha.expire", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.lingniu.idp.exception.user;
|
||||||
|
|
||||||
|
import org.lingniu.idp.exception.base.BaseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息异常类
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class UserException extends BaseException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public UserException(String code, Object[] args)
|
||||||
|
{
|
||||||
|
super("user", code, args, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.lingniu.idp.exception.user;
|
||||||
|
|
||||||
|
import org.lingniu.idp.exception.user.UserException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户不存在异常类
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class UserNotExistsException extends UserException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public UserNotExistsException()
|
||||||
|
{
|
||||||
|
super("user.not.exists", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.lingniu.idp.exception.user;
|
||||||
|
|
||||||
|
import org.lingniu.idp.exception.user.UserException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户密码不正确或不符合规范异常类
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class UserPasswordNotMatchException extends UserException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public UserPasswordNotMatchException()
|
||||||
|
{
|
||||||
|
super("user.password.not.match", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.lingniu.idp.exception.user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户错误最大次数异常类
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class UserPasswordRetryLimitExceedException extends UserException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime)
|
||||||
|
{
|
||||||
|
super("user.password.retry.limit.exceed", new Object[] { retryLimitCount, lockTime });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package org.lingniu.idp.manager;
|
||||||
|
|
||||||
|
import org.lingniu.idp.utils.Threads;
|
||||||
|
import org.lingniu.idp.utils.spring.SpringUtils;
|
||||||
|
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步任务管理器
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class AsyncManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 操作延迟10毫秒
|
||||||
|
*/
|
||||||
|
private final int OPERATE_DELAY_TIME = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步操作任务调度线程池
|
||||||
|
*/
|
||||||
|
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单例模式
|
||||||
|
*/
|
||||||
|
private AsyncManager(){}
|
||||||
|
|
||||||
|
private static AsyncManager me = new AsyncManager();
|
||||||
|
|
||||||
|
public static AsyncManager me()
|
||||||
|
{
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行任务
|
||||||
|
*
|
||||||
|
* @param task 任务
|
||||||
|
*/
|
||||||
|
public void execute(TimerTask task)
|
||||||
|
{
|
||||||
|
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止任务线程池
|
||||||
|
*/
|
||||||
|
public void shutdown()
|
||||||
|
{
|
||||||
|
Threads.shutdownAndAwaitTermination(executor);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.lingniu.idp.manager;
|
||||||
|
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确保应用退出时能关闭后台线程
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ShutdownManager
|
||||||
|
{
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger("sys-user");
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
shutdownAsyncManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止异步执行任务
|
||||||
|
*/
|
||||||
|
private void shutdownAsyncManager()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.info("====关闭后台任务任务线程池====");
|
||||||
|
AsyncManager.me().shutdown();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package org.lingniu.idp.manager.factory;
|
||||||
|
import org.lingniu.idp.constant.Constants;
|
||||||
|
import org.lingniu.idp.service.ISysLogininforService;
|
||||||
|
import org.lingniu.idp.service.ISysOperLogService;
|
||||||
|
import org.lingniu.idp.utils.LogUtils;
|
||||||
|
import org.lingniu.idp.utils.ServletUtils;
|
||||||
|
import org.lingniu.idp.utils.StringUtils;
|
||||||
|
import org.lingniu.idp.utils.http.UserAgentUtils;
|
||||||
|
import org.lingniu.idp.utils.ip.AddressUtils;
|
||||||
|
import org.lingniu.idp.utils.ip.IpUtils;
|
||||||
|
import org.lingniu.idp.utils.spring.SpringUtils;
|
||||||
|
|
||||||
|
import org.lingniu.idp.model.entity.SysLogininfor;
|
||||||
|
import org.lingniu.idp.model.entity.SysOperLog;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步工厂(产生任务用)
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
public class AsyncFactory
|
||||||
|
{
|
||||||
|
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录登录信息
|
||||||
|
*
|
||||||
|
* @param username 用户名
|
||||||
|
* @param status 状态
|
||||||
|
* @param message 消息
|
||||||
|
* @param args 列表
|
||||||
|
* @return 任务task
|
||||||
|
*/
|
||||||
|
public static TimerTask recordLogininfor(final String username, final String status, final String message,
|
||||||
|
final Object... args)
|
||||||
|
{
|
||||||
|
final String userAgent = ServletUtils.getRequest().getHeader("User-Agent");
|
||||||
|
final String ip = IpUtils.getIpAddr();
|
||||||
|
return new TimerTask()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
String address = AddressUtils.getRealAddressByIP(ip);
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
s.append(LogUtils.getBlock(ip));
|
||||||
|
s.append(address);
|
||||||
|
s.append(LogUtils.getBlock(username));
|
||||||
|
s.append(LogUtils.getBlock(status));
|
||||||
|
s.append(LogUtils.getBlock(message));
|
||||||
|
// 打印信息到日志
|
||||||
|
sys_user_logger.info(s.toString(), args);
|
||||||
|
// 获取客户端操作系统
|
||||||
|
String os = UserAgentUtils.getOperatingSystem(userAgent);
|
||||||
|
// 获取客户端浏览器
|
||||||
|
String browser = UserAgentUtils.getBrowser(userAgent);
|
||||||
|
// 封装对象
|
||||||
|
SysLogininfor logininfor = new SysLogininfor();
|
||||||
|
logininfor.setUserName(username);
|
||||||
|
logininfor.setIpaddr(ip);
|
||||||
|
logininfor.setLoginLocation(address);
|
||||||
|
logininfor.setBrowser(browser);
|
||||||
|
logininfor.setOs(os);
|
||||||
|
logininfor.setMsg(message);
|
||||||
|
// 日志状态
|
||||||
|
if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
|
||||||
|
{
|
||||||
|
logininfor.setStatus(Constants.SUCCESS);
|
||||||
|
}
|
||||||
|
else if (Constants.LOGIN_FAIL.equals(status))
|
||||||
|
{
|
||||||
|
logininfor.setStatus(Constants.FAIL);
|
||||||
|
}
|
||||||
|
// 插入数据
|
||||||
|
SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志记录
|
||||||
|
*
|
||||||
|
* @param operLog 操作日志信息
|
||||||
|
* @return 任务task
|
||||||
|
*/
|
||||||
|
public static TimerTask recordOper(final SysOperLog operLog)
|
||||||
|
{
|
||||||
|
return new TimerTask()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
// 远程查询操作地点
|
||||||
|
operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
|
||||||
|
SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.lingniu.idp.model.entity.SysConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数配置 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysConfigMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 查询参数配置信息
|
||||||
|
*
|
||||||
|
* @param config 参数配置信息
|
||||||
|
* @return 参数配置信息
|
||||||
|
*/
|
||||||
|
public SysConfig selectConfig(SysConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过ID查询配置
|
||||||
|
*
|
||||||
|
* @param configId 参数ID
|
||||||
|
* @return 参数配置信息
|
||||||
|
*/
|
||||||
|
public SysConfig selectConfigById(Long configId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询参数配置列表
|
||||||
|
*
|
||||||
|
* @param config 参数配置信息
|
||||||
|
* @return 参数配置集合
|
||||||
|
*/
|
||||||
|
public List<SysConfig> selectConfigList(SysConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据键名查询参数配置信息
|
||||||
|
*
|
||||||
|
* @param configKey 参数键名
|
||||||
|
* @return 参数配置信息
|
||||||
|
*/
|
||||||
|
public SysConfig checkConfigKeyUnique(String configKey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增参数配置
|
||||||
|
*
|
||||||
|
* @param config 参数配置信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertConfig(SysConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改参数配置
|
||||||
|
*
|
||||||
|
* @param config 参数配置信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateConfig(SysConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除参数配置
|
||||||
|
*
|
||||||
|
* @param configId 参数ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteConfigById(Long configId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除参数信息
|
||||||
|
*
|
||||||
|
* @param configIds 需要删除的参数ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteConfigByIds(Long[] configIds);
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.lingniu.idp.model.entity.SysDept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门管理 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysDeptMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 查询部门管理数据
|
||||||
|
*
|
||||||
|
* @param dept 部门信息
|
||||||
|
* @return 部门信息集合
|
||||||
|
*/
|
||||||
|
public List<SysDept> selectDeptList(SysDept dept);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据角色ID查询部门树信息
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @param deptCheckStrictly 部门树选择项是否关联显示
|
||||||
|
* @return 选中部门列表
|
||||||
|
*/
|
||||||
|
public List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据部门ID查询信息
|
||||||
|
*
|
||||||
|
* @param deptId 部门ID
|
||||||
|
* @return 部门信息
|
||||||
|
*/
|
||||||
|
public SysDept selectDeptById(Long deptId);
|
||||||
|
public List<SysDept> selectDeptListByUserRole(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询所有子部门
|
||||||
|
*
|
||||||
|
* @param deptId 部门ID
|
||||||
|
* @return 部门列表
|
||||||
|
*/
|
||||||
|
public List<SysDept> selectChildrenDeptById(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询所有子部门(正常状态)
|
||||||
|
*
|
||||||
|
* @param deptId 部门ID
|
||||||
|
* @return 子部门数
|
||||||
|
*/
|
||||||
|
public int selectNormalChildrenDeptById(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存在子节点
|
||||||
|
*
|
||||||
|
* @param deptId 部门ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int hasChildByDeptId(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询部门是否存在用户
|
||||||
|
*
|
||||||
|
* @param deptId 部门ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int checkDeptExistUser(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验部门名称是否唯一
|
||||||
|
*
|
||||||
|
* @param deptName 部门名称
|
||||||
|
* @param parentId 父部门ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增部门信息
|
||||||
|
*
|
||||||
|
* @param dept 部门信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertDept(SysDept dept);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改部门信息
|
||||||
|
*
|
||||||
|
* @param dept 部门信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateDept(SysDept dept);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改所在部门正常状态
|
||||||
|
*
|
||||||
|
* @param deptIds 部门ID组
|
||||||
|
*/
|
||||||
|
public void updateDeptStatusNormal(Long[] deptIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改子元素关系
|
||||||
|
*
|
||||||
|
* @param depts 子元素
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateDeptChildren(@Param("depts") List<SysDept> depts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除部门管理信息
|
||||||
|
*
|
||||||
|
* @param deptId 部门ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteDeptById(Long deptId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.lingniu.idp.model.entity.SysLogininfor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统访问日志情况信息 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysLogininforMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 新增系统登录日志
|
||||||
|
*
|
||||||
|
* @param logininfor 访问日志对象
|
||||||
|
*/
|
||||||
|
public void insertLogininfor(SysLogininfor logininfor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询系统登录日志集合
|
||||||
|
*
|
||||||
|
* @param logininfor 访问日志对象
|
||||||
|
* @return 登录记录集合
|
||||||
|
*/
|
||||||
|
public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除系统登录日志
|
||||||
|
*
|
||||||
|
* @param infoIds 需要删除的登录日志ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteLogininforByIds(Long[] infoIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空系统登录日志
|
||||||
|
*
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int cleanLogininfor();
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.lingniu.idp.model.entity.SysMenu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单表 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysMenuMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 查询系统菜单列表
|
||||||
|
*
|
||||||
|
* @param menu 菜单信息
|
||||||
|
* @return 菜单列表
|
||||||
|
*/
|
||||||
|
public List<SysMenu> selectMenuList(SysMenu menu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户所有权限
|
||||||
|
*
|
||||||
|
* @return 权限列表
|
||||||
|
*/
|
||||||
|
public List<String> selectMenuPerms();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户查询系统菜单列表
|
||||||
|
*
|
||||||
|
* @param menu 菜单信息
|
||||||
|
* @return 菜单列表
|
||||||
|
*/
|
||||||
|
public List<SysMenu> selectMenuListByUserId(SysMenu menu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据角色ID查询权限
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @return 权限列表
|
||||||
|
*/
|
||||||
|
public List<String> selectMenuPermsByRoleId(Long roleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询权限
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 权限列表
|
||||||
|
*/
|
||||||
|
public List<String> selectMenuPermsByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询菜单
|
||||||
|
*
|
||||||
|
* @return 菜单列表
|
||||||
|
*/
|
||||||
|
public List<SysMenu> selectMenuTreeAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询菜单
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 菜单列表
|
||||||
|
*/
|
||||||
|
public List<SysMenu> selectMenuTreeByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据角色ID查询菜单树信息
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @param menuCheckStrictly 菜单树选择项是否关联显示
|
||||||
|
* @return 选中菜单列表
|
||||||
|
*/
|
||||||
|
public List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据菜单ID查询信息
|
||||||
|
*
|
||||||
|
* @param menuId 菜单ID
|
||||||
|
* @return 菜单信息
|
||||||
|
*/
|
||||||
|
public SysMenu selectMenuById(Long menuId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存在菜单子节点
|
||||||
|
*
|
||||||
|
* @param menuId 菜单ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int hasChildByMenuId(Long menuId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增菜单信息
|
||||||
|
*
|
||||||
|
* @param menu 菜单信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertMenu(SysMenu menu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改菜单信息
|
||||||
|
*
|
||||||
|
* @param menu 菜单信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateMenu(SysMenu menu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除菜单管理信息
|
||||||
|
*
|
||||||
|
* @param menuId 菜单ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteMenuById(Long menuId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验菜单名称是否唯一
|
||||||
|
*
|
||||||
|
* @param menuName 菜单名称
|
||||||
|
* @param parentId 父菜单ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.lingniu.idp.model.entity.SysOperLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysOperLogMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 新增操作日志
|
||||||
|
*
|
||||||
|
* @param operLog 操作日志对象
|
||||||
|
*/
|
||||||
|
public void insertOperlog(SysOperLog operLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询系统操作日志集合
|
||||||
|
*
|
||||||
|
* @param operLog 操作日志对象
|
||||||
|
* @return 操作日志集合
|
||||||
|
*/
|
||||||
|
public List<SysOperLog> selectOperLogList(SysOperLog operLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除系统操作日志
|
||||||
|
*
|
||||||
|
* @param operIds 需要删除的操作日志ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteOperLogByIds(Long[] operIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询操作日志详细
|
||||||
|
*
|
||||||
|
* @param operId 操作ID
|
||||||
|
* @return 操作日志对象
|
||||||
|
*/
|
||||||
|
public SysOperLog selectOperLogById(Long operId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空操作日志
|
||||||
|
*/
|
||||||
|
public void cleanOperLog();
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.lingniu.idp.model.entity.SysPost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 岗位信息 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysPostMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 查询岗位数据集合
|
||||||
|
*
|
||||||
|
* @param post 岗位信息
|
||||||
|
* @return 岗位数据集合
|
||||||
|
*/
|
||||||
|
public List<SysPost> selectPostList(SysPost post);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有岗位
|
||||||
|
*
|
||||||
|
* @return 岗位列表
|
||||||
|
*/
|
||||||
|
public List<SysPost> selectPostAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过岗位ID查询岗位信息
|
||||||
|
*
|
||||||
|
* @param postId 岗位ID
|
||||||
|
* @return 角色对象信息
|
||||||
|
*/
|
||||||
|
public SysPost selectPostById(Long postId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID获取岗位选择框列表
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 选中岗位ID列表
|
||||||
|
*/
|
||||||
|
public List<Long> selectPostListByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户所属岗位组
|
||||||
|
*
|
||||||
|
* @param userName 用户名
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public List<SysPost> selectPostsByUserName(String userName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除岗位信息
|
||||||
|
*
|
||||||
|
* @param postId 岗位ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deletePostById(Long postId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除岗位信息
|
||||||
|
*
|
||||||
|
* @param postIds 需要删除的岗位ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deletePostByIds(Long[] postIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改岗位信息
|
||||||
|
*
|
||||||
|
* @param post 岗位信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updatePost(SysPost post);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增岗位信息
|
||||||
|
*
|
||||||
|
* @param post 岗位信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertPost(SysPost post);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验岗位名称
|
||||||
|
*
|
||||||
|
* @param postName 岗位名称
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public SysPost checkPostNameUnique(String postName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验岗位编码
|
||||||
|
*
|
||||||
|
* @param postCode 岗位编码
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public SysPost checkPostCodeUnique(String postCode);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.lingniu.idp.model.entity.SysRoleDept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色与部门关联表 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysRoleDeptMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 通过角色ID删除角色和部门关联
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteRoleDeptByRoleId(Long roleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除角色部门关联信息
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteRoleDept(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询部门使用数量
|
||||||
|
*
|
||||||
|
* @param deptId 部门ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int selectCountRoleDeptByDeptId(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增角色部门信息
|
||||||
|
*
|
||||||
|
* @param roleDeptList 角色部门列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int batchRoleDept(List<SysRoleDept> roleDeptList);
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.lingniu.idp.model.entity.SysRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色表 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysRoleMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 根据条件分页查询角色数据
|
||||||
|
*
|
||||||
|
* @param role 角色信息
|
||||||
|
* @return 角色数据集合信息
|
||||||
|
*/
|
||||||
|
public List<SysRole> selectRoleList(SysRole role);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询角色
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 角色列表
|
||||||
|
*/
|
||||||
|
public List<SysRole> selectRolePermissionByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有角色
|
||||||
|
*
|
||||||
|
* @return 角色列表
|
||||||
|
*/
|
||||||
|
public List<SysRole> selectRoleAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID获取角色选择框列表
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 选中角色ID列表
|
||||||
|
*/
|
||||||
|
public List<Long> selectRoleListByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过角色ID查询角色
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @return 角色对象信息
|
||||||
|
*/
|
||||||
|
public SysRole selectRoleById(Long roleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询角色
|
||||||
|
*
|
||||||
|
* @param userName 用户名
|
||||||
|
* @return 角色列表
|
||||||
|
*/
|
||||||
|
public List<SysRole> selectRolesByUserName(String userName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验角色名称是否唯一
|
||||||
|
*
|
||||||
|
* @param roleName 角色名称
|
||||||
|
* @return 角色信息
|
||||||
|
*/
|
||||||
|
public SysRole checkRoleNameUnique(String roleName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验角色权限是否唯一
|
||||||
|
*
|
||||||
|
* @param roleKey 角色权限
|
||||||
|
* @return 角色信息
|
||||||
|
*/
|
||||||
|
public SysRole checkRoleKeyUnique(String roleKey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改角色信息
|
||||||
|
*
|
||||||
|
* @param role 角色信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateRole(SysRole role);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增角色信息
|
||||||
|
*
|
||||||
|
* @param role 角色信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertRole(SysRole role);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过角色ID删除角色
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteRoleById(Long roleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除角色信息
|
||||||
|
*
|
||||||
|
* @param roleIds 需要删除的角色ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteRoleByIds(Long[] roleIds);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.lingniu.idp.model.entity.SysRoleMenu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色与菜单关联表 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysRoleMenuMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 查询菜单使用数量
|
||||||
|
*
|
||||||
|
* @param menuId 菜单ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int checkMenuExistRole(Long menuId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过角色ID删除角色和菜单关联
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteRoleMenuByRoleId(Long roleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除角色菜单关联信息
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteRoleMenu(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增角色菜单信息
|
||||||
|
*
|
||||||
|
* @param roleMenuList 角色菜单列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int batchRoleMenu(List<SysRoleMenu> roleMenuList);
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.lingniu.idp.model.entity.SysUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户表 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysUserMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 根据条件分页查询用户列表
|
||||||
|
*
|
||||||
|
* @param sysUser 用户信息
|
||||||
|
* @return 用户信息集合信息
|
||||||
|
*/
|
||||||
|
public List<SysUser> selectUserList(SysUser sysUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件分页查询已配用户角色列表
|
||||||
|
*
|
||||||
|
* @param user 用户信息
|
||||||
|
* @return 用户信息集合信息
|
||||||
|
*/
|
||||||
|
public List<SysUser> selectAllocatedList(SysUser user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件分页查询未分配用户角色列表
|
||||||
|
*
|
||||||
|
* @param user 用户信息
|
||||||
|
* @return 用户信息集合信息
|
||||||
|
*/
|
||||||
|
public List<SysUser> selectUnallocatedList(SysUser user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过用户名查询用户
|
||||||
|
*
|
||||||
|
* @param userName 用户名
|
||||||
|
* @return 用户对象信息
|
||||||
|
*/
|
||||||
|
public SysUser selectUserByUserName(String userName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过用户ID查询用户
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 用户对象信息
|
||||||
|
*/
|
||||||
|
public SysUser selectUserById(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增用户信息
|
||||||
|
*
|
||||||
|
* @param user 用户信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertUser(SysUser user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户信息
|
||||||
|
*
|
||||||
|
* @param user 用户信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateUser(SysUser user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户头像
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param avatar 头像地址
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateUserAvatar(@Param("userId") Long userId, @Param("avatar") String avatar);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户状态
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param status 状态
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateUserStatus(@Param("userId") Long userId, @Param("status") String status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户登录信息(IP和登录时间)
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param loginIp 登录IP地址
|
||||||
|
* @param loginDate 登录时间
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateLoginInfo(@Param("userId") Long userId, @Param("loginIp") String loginIp, @Param("loginDate") Date loginDate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置用户密码
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param password 密码
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int resetUserPwd(@Param("userId") Long userId, @Param("password") String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过用户ID删除用户
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteUserById(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除用户信息
|
||||||
|
*
|
||||||
|
* @param userIds 需要删除的用户ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteUserByIds(Long[] userIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验用户名称是否唯一
|
||||||
|
*
|
||||||
|
* @param userName 用户名称
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public SysUser checkUserNameUnique(String userName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验手机号码是否唯一
|
||||||
|
*
|
||||||
|
* @param phonenumber 手机号码
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public SysUser checkPhoneUnique(String phonenumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验email是否唯一
|
||||||
|
*
|
||||||
|
* @param email 用户邮箱
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public SysUser checkEmailUnique(String email);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.lingniu.idp.model.entity.SysUserPost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户与岗位关联表 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysUserPostMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 通过用户ID删除用户和岗位关联
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteUserPostByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过岗位ID查询岗位使用数量
|
||||||
|
*
|
||||||
|
* @param postId 岗位ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int countUserPostById(Long postId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除用户和岗位关联
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteUserPost(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增用户岗位信息
|
||||||
|
*
|
||||||
|
* @param userPostList 用户岗位列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int batchUserPost(List<SysUserPost> userPostList);
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package org.lingniu.idp.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.lingniu.idp.model.entity.SysUserRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户与角色关联表 数据层
|
||||||
|
*
|
||||||
|
* @author portal
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface SysUserRoleMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 通过用户ID删除用户和角色关联
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteUserRoleByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除用户和角色关联
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteUserRole(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过角色ID查询角色使用数量
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int countUserRoleByRoleId(Long roleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增用户角色信息
|
||||||
|
*
|
||||||
|
* @param userRoleList 用户角色列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int batchUserRole(List<SysUserRole> userRoleList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户和角色关联信息
|
||||||
|
*
|
||||||
|
* @param userRole 用户和角色关联信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteUserRoleInfo(SysUserRole userRole);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量取消授权用户角色
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @param userIds 需要删除的用户数据ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user