mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-10-15 18:54:54 +08:00
merge dev into master
v1.39.0 update Created-by: shengzhang_ Author-id: 774020 MR-id: 152152 Commit-by: click33;zhongjun;goodsWox;grasse;巴掌大叔;cuiguiyang Merged-by: shengzhang_ E2E-issues: Description: 兼容请求/oauth2/token接口时Basic中携带clientId和clientSecret的场景 更新赞助者列表 补全 dromara 项目列表 更新赞助列表信息 !308 处理解析 JWT 时的 JSONException ... See merge request: dromara/sa-token!2
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://sa-token.cc/logo.png" width="150" height="150">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.38.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.39.0</h1>
|
||||
<h4 align="center">一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h4>
|
||||
<p align="center">
|
||||
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
|
||||
@@ -185,6 +185,7 @@ Sa-Token-OAuth2 模块分为四种授权模式,解决不同场景下的授权
|
||||
- [[ hippo4j ]](https://gitee.com/agentart/hippo4j):强大的动态线程池框架,附带监控报警功能。
|
||||
- [[ hertzbeat ]](https://gitee.com/dromara/hertzbeat):易用友好的开源实时监控告警系统,无需Agent,高性能集群,强大自定义监控能力。
|
||||
- [[ Solon ]](https://gitee.com/noear/solon):一个更现代感的应用开发框架:更快、更小、更自由。
|
||||
- [[ Chat2DB ]](https://github.com/chat2db/Chat2DB):一个AI驱动的数据库管理和BI工具,支持Mysql、pg、Oracle、Redis等22种数据库的管理。
|
||||
|
||||
|
||||
|
||||
@@ -198,7 +199,7 @@ Sa-Token-OAuth2 模块分为四种授权模式,解决不同场景下的授权
|
||||
### 交流群
|
||||
<!-- QQ交流群:685792424 [点击加入](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Y05Ld4125W92YSwZ0gA8e3RhG9Q4Vsfx&authKey=IomXuIuhP9g8G7l%2ByfkrRsS7i%2Fna0lIBpkTXxx%2BQEaz0NNEyJq00kgeiC4dUyNLS&noverify=0&group_code=685792424)-->
|
||||
|
||||
QQ交流群:936523917 [点击加入](https://qm.qq.com/q/xfoMJA5Az0)
|
||||
QQ交流群:823181187 [点击加入](https://qm.qq.com/q/EBIJVZBVGE)
|
||||
|
||||
微信交流群:
|
||||
|
||||
|
2
pom.xml
2
pom.xml
@@ -37,7 +37,7 @@
|
||||
|
||||
<!-- 一些属性 -->
|
||||
<properties>
|
||||
<revision>1.38.0</revision>
|
||||
<revision>1.39.0</revision>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
|
||||
|
@@ -13,7 +13,7 @@
|
||||
<url>https://github.com/dromara/sa-token</url>
|
||||
|
||||
<properties>
|
||||
<revision>1.38.0</revision>
|
||||
<revision>1.39.0</revision>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@@ -39,13 +39,6 @@ public @interface SaCheckOr {
|
||||
*/
|
||||
SaCheckLogin[] login() default {};
|
||||
|
||||
/**
|
||||
* 设定 @SaCheckPermission,参考 {@link SaCheckPermission}
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
SaCheckPermission[] permission() default {};
|
||||
|
||||
/**
|
||||
* 设定 @SaCheckRole,参考 {@link SaCheckRole}
|
||||
*
|
||||
@@ -53,6 +46,13 @@ public @interface SaCheckOr {
|
||||
*/
|
||||
SaCheckRole[] role() default {};
|
||||
|
||||
/**
|
||||
* 设定 @SaCheckPermission,参考 {@link SaCheckPermission}
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
SaCheckPermission[] permission() default {};
|
||||
|
||||
/**
|
||||
* 设定 @SaCheckSafe,参考 {@link SaCheckSafe}
|
||||
*
|
||||
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 所有注解处理器的父接口
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public interface SaAnnotationHandlerInterface<T extends Annotation> {
|
||||
|
||||
/**
|
||||
* 获取所要处理的注解类型
|
||||
* @return /
|
||||
*/
|
||||
Class<T> getHandlerAnnotationClass();
|
||||
|
||||
/**
|
||||
* 所需要执行的校验方法
|
||||
* @param at 注解对象
|
||||
* @param method 被标注的注解的方法引用
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default void check(Annotation at, Method method) {
|
||||
checkMethod((T) at, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 所需要执行的校验方法(转换类型后)
|
||||
* @param at 注解对象
|
||||
* @param method 被标注的注解的方法引用
|
||||
*/
|
||||
void checkMethod(T at, Method method);
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckDisable;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckDisable 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaCheckDisableHandler implements SaAnnotationHandlerInterface<SaCheckDisable> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckDisable> getHandlerAnnotationClass() {
|
||||
return SaCheckDisable.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckDisable at, Method method) {
|
||||
_checkMethod(at.type(), at.value(), at.level());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String type, String[] value, int level) {
|
||||
StpLogic stpLogic = SaManager.getStpLogic(type, false);
|
||||
|
||||
Object loginId = stpLogic.getLoginId();
|
||||
for (String service : value) {
|
||||
stpLogic.checkDisableLevel(loginId, service, level);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckHttpBasic;
|
||||
import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckHttpBasic 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaCheckHttpBasicHandler implements SaAnnotationHandlerInterface<SaCheckHttpBasic> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckHttpBasic> getHandlerAnnotationClass() {
|
||||
return SaCheckHttpBasic.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckHttpBasic at, Method method) {
|
||||
_checkMethod(at.realm(), at.account());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String realm, String account) {
|
||||
SaHttpBasicUtil.check(realm, account);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckHttpDigest;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.httpauth.digest.SaHttpDigestUtil;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckHttpDigest 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaCheckHttpDigestHandler implements SaAnnotationHandlerInterface<SaCheckHttpDigest> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckHttpDigest> getHandlerAnnotationClass() {
|
||||
return SaCheckHttpDigest.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckHttpDigest at, Method method) {
|
||||
_checkMethod(at.username(), at.password(), at.realm(), at.value());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String username, String password, String realm, String value) {
|
||||
// 如果配置了 value,则以 value 优先
|
||||
if(SaFoxUtil.isNotEmpty(value)){
|
||||
String[] arr = value.split(":");
|
||||
if(arr.length != 2){
|
||||
throw new SaTokenException("注解参数配置错误,格式应如:username:password");
|
||||
}
|
||||
SaHttpDigestUtil.check(arr[0], arr[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果配置了 username,则分别获取参数
|
||||
if(SaFoxUtil.isNotEmpty(username)){
|
||||
SaHttpDigestUtil.check(username, password, realm);
|
||||
return;
|
||||
}
|
||||
|
||||
// 都没有配置,则根据全局配置参数进行校验
|
||||
SaHttpDigestUtil.check();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckLogin 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaCheckLoginHandler implements SaAnnotationHandlerInterface<SaCheckLogin> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckLogin> getHandlerAnnotationClass() {
|
||||
return SaCheckLogin.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckLogin at, Method method) {
|
||||
_checkMethod(at.type());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String type) {
|
||||
StpLogic stpLogic = SaManager.getStpLogic(type, false);
|
||||
|
||||
stpLogic.checkLogin();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.*;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.strategy.SaAnnotationStrategy;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckOr 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaCheckOrHandler implements SaAnnotationHandlerInterface<SaCheckOr> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckOr> getHandlerAnnotationClass() {
|
||||
return SaCheckOr.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckOr at, Method method) {
|
||||
_checkMethod(at.login(), at.role(), at.permission(), at.safe(), at.httpBasic(), at.httpDigest(), at.disable(), method);
|
||||
}
|
||||
|
||||
public static void _checkMethod(
|
||||
SaCheckLogin[] login,
|
||||
SaCheckRole[] role,
|
||||
SaCheckPermission[] permission,
|
||||
SaCheckSafe[] safe,
|
||||
SaCheckHttpBasic[] httpBasic,
|
||||
SaCheckHttpDigest[] httpDigest,
|
||||
SaCheckDisable[] disable,
|
||||
Method method
|
||||
) {
|
||||
// 先把所有注解塞到一个 list 里
|
||||
List<Annotation> annotationList = new ArrayList<>();
|
||||
annotationList.addAll(Arrays.asList(login));
|
||||
annotationList.addAll(Arrays.asList(role));
|
||||
annotationList.addAll(Arrays.asList(permission));
|
||||
annotationList.addAll(Arrays.asList(safe));
|
||||
annotationList.addAll(Arrays.asList(disable));
|
||||
annotationList.addAll(Arrays.asList(httpBasic));
|
||||
annotationList.addAll(Arrays.asList(httpDigest));
|
||||
|
||||
// 如果 atList 为空,说明 SaCheckOr 上不包含任何注解校验,我们直接跳过即可
|
||||
if(annotationList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 逐个开始校验 >>>
|
||||
List<SaTokenException> errorList = new ArrayList<>();
|
||||
for (Annotation item : annotationList) {
|
||||
try {
|
||||
SaAnnotationStrategy.instance.annotationHandlerMap.get(item.annotationType()).check(item, method);
|
||||
// 只要有一个校验通过,就可以直接返回了
|
||||
return;
|
||||
} catch (SaTokenException e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行至此,说明所有注解校验都通过不了,此时 errorList 里面会有多个异常,我们随便抛出一个即可
|
||||
throw errorList.get(0);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckPermission 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaCheckPermissionHandler implements SaAnnotationHandlerInterface<SaCheckPermission> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckPermission> getHandlerAnnotationClass() {
|
||||
return SaCheckPermission.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckPermission at, Method method) {
|
||||
_checkMethod(at.type(), at.value(), at.mode(), at.orRole());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String type, String[] value, SaMode mode, String[] orRole) {
|
||||
StpLogic stpLogic = SaManager.getStpLogic(type, false);
|
||||
|
||||
String[] permissionArray = value;
|
||||
try {
|
||||
if(mode == SaMode.AND) {
|
||||
stpLogic.checkPermissionAnd(permissionArray);
|
||||
} else {
|
||||
stpLogic.checkPermissionOr(permissionArray);
|
||||
}
|
||||
} catch (NotPermissionException e) {
|
||||
// 权限认证校验未通过,再开始角色认证校验
|
||||
for (String role : orRole) {
|
||||
String[] rArr = SaFoxUtil.convertStringToArray(role);
|
||||
// 某一项 role 认证通过,则可以提前退出了,代表通过
|
||||
if (stpLogic.hasRoleAnd(rArr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckRole 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaCheckRoleHandler implements SaAnnotationHandlerInterface<SaCheckRole> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckRole> getHandlerAnnotationClass() {
|
||||
return SaCheckRole.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckRole at, Method method) {
|
||||
_checkMethod(at.type(), at.value(), at.mode());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String type, String[] value, SaMode mode) {
|
||||
StpLogic stpLogic = SaManager.getStpLogic(type, false);
|
||||
|
||||
String[] roleArray = value;
|
||||
if(mode == SaMode.AND) {
|
||||
stpLogic.checkRoleAnd(roleArray);
|
||||
} else {
|
||||
stpLogic.checkRoleOr(roleArray);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckSafe;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckSafe 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaCheckSafeHandler implements SaAnnotationHandlerInterface<SaCheckSafe> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckSafe> getHandlerAnnotationClass() {
|
||||
return SaCheckSafe.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckSafe at, Method method) {
|
||||
_checkMethod(at.type(), at.value());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String type, String value) {
|
||||
StpLogic stpLogic = SaManager.getStpLogic(type, false);
|
||||
|
||||
stpLogic.checkSafe(value);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaIgnore 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/2
|
||||
*/
|
||||
public class SaIgnoreHandler implements SaAnnotationHandlerInterface<SaIgnore> {
|
||||
|
||||
@Override
|
||||
public Class<SaIgnore> getHandlerAnnotationClass() {
|
||||
return SaIgnore.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaIgnore at, Method method) {
|
||||
_checkMethod();
|
||||
}
|
||||
|
||||
public static void _checkMethod() {
|
||||
SaRouter.stop();
|
||||
}
|
||||
|
||||
}
|
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.basic;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.NotBasicAuthException;
|
||||
import cn.dev33.satoken.secure.SaBase64Util;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* <h2> 已更换至包:cn.dev33.satoken.httpauth.basic </h2>
|
||||
* <h2> 已更换名称:SaHttpBasicTemplate </h2>
|
||||
*
|
||||
* Sa-Token Http Basic 认证模块
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.26.0
|
||||
*/
|
||||
@Deprecated
|
||||
public class SaBasicTemplate {
|
||||
|
||||
/**
|
||||
* 默认的 Realm 领域名称
|
||||
*/
|
||||
public static final String DEFAULT_REALM = "Sa-Token";
|
||||
|
||||
/**
|
||||
* 在校验失败时,设置响应头,并抛出异常
|
||||
* @param realm 领域
|
||||
*/
|
||||
public void throwNotBasicAuthException(String realm) {
|
||||
SaHolder.getResponse().setStatus(401).setHeader("WWW-Authenticate", "Basic Realm=" + realm);
|
||||
throw new NotBasicAuthException().setCode(SaErrorCode.CODE_10311);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器提交的 Basic 参数 (裁剪掉前缀并解码)
|
||||
* @return 值
|
||||
*/
|
||||
public String getAuthorizationValue() {
|
||||
|
||||
// 获取前端提交的请求头 Authorization 参数
|
||||
String authorization = SaHolder.getRequest().getHeader("Authorization");
|
||||
|
||||
// 如果不是以 Basic 作为前缀,则视为无效
|
||||
if(authorization == null || ! authorization.startsWith("Basic ")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 裁剪前缀并解码
|
||||
return SaBase64Util.decode(authorization.substring(6));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对当前会话进行 Basic 校验(使用全局配置的账号密码),校验不通过则抛出异常
|
||||
*/
|
||||
public void check() {
|
||||
check(DEFAULT_REALM, SaManager.getConfig().getBasic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 对当前会话进行 Basic 校验(手动设置账号密码),校验不通过则抛出异常
|
||||
* @param account 账号(格式为 user:password)
|
||||
*/
|
||||
public void check(String account) {
|
||||
check(DEFAULT_REALM, account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对当前会话进行 Basic 校验(手动设置 Realm 和 账号密码),校验不通过则抛出异常
|
||||
* @param realm 领域
|
||||
* @param account 账号(格式为 user:password)
|
||||
*/
|
||||
public void check(String realm, String account) {
|
||||
if(SaFoxUtil.isEmpty(account)) {
|
||||
account = SaManager.getConfig().getBasic();
|
||||
}
|
||||
String authorization = getAuthorizationValue();
|
||||
if(SaFoxUtil.isEmpty(authorization) || ! authorization.equals(account)) {
|
||||
throwNotBasicAuthException(realm);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.basic;
|
||||
|
||||
/**
|
||||
* <h2> 已更换至包:cn.dev33.satoken.httpauth.basic </h2>
|
||||
* <h2> 已更换名称:SaHttpBasicUtil </h2>
|
||||
*
|
||||
* Sa-Token Http Basic 认证模块,Util 工具类
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.26.0
|
||||
*/
|
||||
@Deprecated
|
||||
public class SaBasicUtil {
|
||||
|
||||
private SaBasicUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 底层使用的 SaBasicTemplate 对象
|
||||
*/
|
||||
public static SaBasicTemplate saBasicTemplate = new SaBasicTemplate();
|
||||
|
||||
/**
|
||||
* 获取浏览器提交的 Basic 参数 (裁剪掉前缀并解码)
|
||||
* @return 值
|
||||
*/
|
||||
public static String getAuthorizationValue() {
|
||||
return saBasicTemplate.getAuthorizationValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对当前会话进行 Basic 校验(使用全局配置的账号密码),校验不通过则抛出异常
|
||||
*/
|
||||
public static void check() {
|
||||
saBasicTemplate.check();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对当前会话进行 Basic 校验(手动设置账号密码),校验不通过则抛出异常
|
||||
* @param account 账号(格式为 user:password)
|
||||
*/
|
||||
public static void check(String account) {
|
||||
saBasicTemplate.check(account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对当前会话进行 Basic 校验(手动设置 Realm 和 账号密码),校验不通过则抛出异常
|
||||
* @param realm 领域
|
||||
* @param account 账号(格式为 user:password)
|
||||
*/
|
||||
public static void check(String realm, String account) {
|
||||
saBasicTemplate.check(realm, account);
|
||||
}
|
||||
|
||||
}
|
@@ -17,6 +17,7 @@ package cn.dev33.satoken.context.model;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.router.SaHttpMethod;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.util.List;
|
||||
@@ -130,6 +131,20 @@ public interface SaRequest {
|
||||
*/
|
||||
String getCookieValue(String name);
|
||||
|
||||
/**
|
||||
* 在 [ Cookie作用域 ] 里获取一个值 (第一个此名称的)
|
||||
* @param name 键
|
||||
* @return 值
|
||||
*/
|
||||
String getCookieFirstValue(String name);
|
||||
|
||||
/**
|
||||
* 在 [ Cookie作用域 ] 里获取一个值 (最后一个此名称的)
|
||||
* @param name 键
|
||||
* @return 值
|
||||
*/
|
||||
String getCookieLastValue(String name);
|
||||
|
||||
/**
|
||||
* 返回当前请求path (不包括上下文名称)
|
||||
* @return /
|
||||
@@ -156,7 +171,25 @@ public interface SaRequest {
|
||||
* @return /
|
||||
*/
|
||||
String getMethod();
|
||||
|
||||
|
||||
/**
|
||||
* 返回当前请求 Method 是否为指定值
|
||||
* @param method method
|
||||
* @return /
|
||||
*/
|
||||
default boolean isMethod(String method) {
|
||||
return getMethod().equals(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前请求 Method 是否为指定值
|
||||
* @param method method
|
||||
* @return /
|
||||
*/
|
||||
default boolean isMethod(SaHttpMethod method) {
|
||||
return getMethod().equals(method.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断此请求是否为 Ajax 异步请求
|
||||
* @return /
|
||||
|
@@ -21,7 +21,7 @@ package cn.dev33.satoken.exception;
|
||||
* @author click33
|
||||
* @since 1.26.0
|
||||
*/
|
||||
public class NotBasicAuthException extends SaTokenException {
|
||||
public class NotHttpBasicAuthException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
@@ -34,7 +34,7 @@ public class NotBasicAuthException extends SaTokenException {
|
||||
/**
|
||||
* 一个异常:代表会话未通过 Http Basic 认证
|
||||
*/
|
||||
public NotBasicAuthException() {
|
||||
public NotHttpBasicAuthException() {
|
||||
super(BE_MESSAGE);
|
||||
}
|
||||
|
@@ -29,6 +29,6 @@ import java.util.function.BiFunction;
|
||||
* @since 1.35.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaGetAnnotationFunction extends BiFunction<AnnotatedElement, Class<? extends Annotation> , Annotation> {
|
||||
public interface SaGetAnnotationFunction extends BiFunction<AnnotatedElement, Class<? extends Annotation>, Annotation> {
|
||||
|
||||
}
|
@@ -18,7 +18,7 @@ package cn.dev33.satoken.httpauth.basic;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.NotBasicAuthException;
|
||||
import cn.dev33.satoken.exception.NotHttpBasicAuthException;
|
||||
import cn.dev33.satoken.secure.SaBase64Util;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
@@ -41,7 +41,7 @@ public class SaHttpBasicTemplate {
|
||||
*/
|
||||
public void throwNotBasicAuthException(String realm) {
|
||||
SaHolder.getResponse().setStatus(401).setHeader("WWW-Authenticate", "Basic Realm=" + realm);
|
||||
throw new NotBasicAuthException().setCode(SaErrorCode.CODE_10311);
|
||||
throw new NotHttpBasicAuthException().setCode(SaErrorCode.CODE_10311);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -263,11 +263,16 @@ public class SaHttpDigestTemplate {
|
||||
check(arr[0], arr[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------- 过期方法 -----------------
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckHttpDigest ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
@Deprecated
|
||||
public void checkByAnnotation(SaCheckHttpDigest at) {
|
||||
|
||||
// 如果配置了 value,则以 value 优先
|
||||
|
@@ -90,11 +90,16 @@ public class SaHttpDigestUtil {
|
||||
saHttpDigestTemplate.check();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------- 过期方法 -----------------
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckHttpDigest ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
@Deprecated
|
||||
public static void checkByAnnotation(SaCheckHttpDigest at) {
|
||||
saHttpDigestTemplate.checkByAnnotation(at);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ package cn.dev33.satoken.listener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
@@ -287,6 +288,16 @@ public class SaTokenEventCenter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件发布:有新的注解处理器载入到框架中
|
||||
* @param handler 注解处理器
|
||||
*/
|
||||
public static void doRegisterAnnotationHandler(SaAnnotationHandlerInterface<?> handler) {
|
||||
for (SaTokenListener listener : listenerList) {
|
||||
listener.doRegisterAnnotationHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件发布:有新的 StpLogic 载入到框架中
|
||||
* @param stpLogic /
|
||||
|
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package cn.dev33.satoken.listener;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
@@ -125,6 +126,12 @@ public interface SaTokenListener {
|
||||
*/
|
||||
default void doRegisterComponent(String compName, Object compObj) {}
|
||||
|
||||
/**
|
||||
* 注册了自定义注解处理器
|
||||
* @param handler 注解处理器
|
||||
*/
|
||||
default void doRegisterAnnotationHandler(SaAnnotationHandlerInterface<?> handler) {}
|
||||
|
||||
/**
|
||||
* StpLogic 对象替换
|
||||
* @param stpLogic /
|
||||
|
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
package cn.dev33.satoken.listener;
|
||||
|
||||
import static cn.dev33.satoken.SaManager.log;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import static cn.dev33.satoken.SaManager.log;
|
||||
|
||||
/**
|
||||
* Sa-Token 侦听器的一个实现:Log 打印
|
||||
*
|
||||
@@ -130,6 +131,17 @@ public class SaTokenListenerForLog implements SaTokenListener {
|
||||
log.info("全局组件 {} 载入成功: {}", compName, canonicalName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册了自定义注解处理器
|
||||
* @param handler 注解处理器
|
||||
*/
|
||||
@Override
|
||||
public void doRegisterAnnotationHandler(SaAnnotationHandlerInterface<?> handler) {
|
||||
if(handler != null) {
|
||||
log.info("注解扩展 @{} (处理器: {})", handler.getHandlerAnnotationClass().getSimpleName(), handler.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StpLogic 对象替换
|
||||
* @param stpLogic /
|
||||
|
@@ -96,7 +96,7 @@ public class SaSession implements SaSetValueInterface, Serializable {
|
||||
/**
|
||||
* 所有挂载数据
|
||||
*/
|
||||
private final Map<String, Object> dataMap = new ConcurrentHashMap<>();
|
||||
private Map<String, Object> dataMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
// ----------------------- 构建相关
|
||||
@@ -522,14 +522,26 @@ public class SaSession implements SaSetValueInterface, Serializable {
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据挂载集合 (改变底层对象引用,将 dataMap 整个对象替换)
|
||||
* @param dataMap 数据集合
|
||||
*
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSession setDataMap(Map<String, Object> dataMap) {
|
||||
this.dataMap = dataMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入数据集合 (不改变底层对象引用,只将此 dataMap 所有数据进行替换)
|
||||
* @param dataMap 数据集合
|
||||
*/
|
||||
public void refreshDataMap(Map<String, Object> dataMap) {
|
||||
public SaSession refreshDataMap(Map<String, Object> dataMap) {
|
||||
this.dataMap.clear();
|
||||
this.dataMap.putAll(dataMap);
|
||||
this.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
//
|
||||
|
@@ -300,6 +300,9 @@ public class SaLoginModel {
|
||||
if(getTimeoutOrGlobalConfig() == SaTokenDao.NEVER_EXPIRE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
if (timeout > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return (int)(long)timeout;
|
||||
}
|
||||
|
||||
|
@@ -36,7 +36,7 @@ import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import cn.dev33.satoken.util.SaValue2Box;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
@@ -590,6 +590,20 @@ public class StpLogic {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定账号 id 的登录会话数据,如果获取不到则创建并返回
|
||||
*
|
||||
* @param id 账号id,建议的类型:(long | int | String)
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public String getOrCreateLoginSession(Object id) {
|
||||
String tokenValue = getTokenValueByLoginId(id);
|
||||
if(tokenValue == null) {
|
||||
tokenValue = createLoginSession(id, new SaLoginModel());
|
||||
}
|
||||
return tokenValue;
|
||||
}
|
||||
|
||||
// --- 注销
|
||||
|
||||
/**
|
||||
@@ -2114,7 +2128,7 @@ public class StpLogic {
|
||||
// 如果该账号的 Account-Session 为 null,说明此账号尚没有客户端在登录,此时返回空集合
|
||||
SaSession session = getSessionByLoginId(loginId, false);
|
||||
if(session == null) {
|
||||
return Collections.emptyList();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 按照设备类型进行筛选
|
||||
@@ -2132,7 +2146,7 @@ public class StpLogic {
|
||||
// 如果该账号的 Account-Session 为 null,说明此账号尚没有客户端在登录,此时返回空集合
|
||||
SaSession session = getSessionByLoginId(loginId, false);
|
||||
if(session == null) {
|
||||
return Collections.emptyList();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 按照设备类型进行筛选
|
||||
@@ -2233,79 +2247,6 @@ public class StpLogic {
|
||||
public List<String> searchTokenSessionId(String keyword, int start, int size, boolean sortType) {
|
||||
return getSaTokenDao().searchData(splicingKeyTokenSession(""), keyword, start, size, sortType);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 注解鉴权 -------------------
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckLogin ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(SaCheckLogin at) {
|
||||
this.checkLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckRole ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(SaCheckRole at) {
|
||||
String[] roleArray = at.value();
|
||||
if(at.mode() == SaMode.AND) {
|
||||
this.checkRoleAnd(roleArray);
|
||||
} else {
|
||||
this.checkRoleOr(roleArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckPermission ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(SaCheckPermission at) {
|
||||
String[] permissionArray = at.value();
|
||||
try {
|
||||
if(at.mode() == SaMode.AND) {
|
||||
this.checkPermissionAnd(permissionArray);
|
||||
} else {
|
||||
this.checkPermissionOr(permissionArray);
|
||||
}
|
||||
} catch (NotPermissionException e) {
|
||||
// 权限认证校验未通过,再开始角色认证校验
|
||||
for (String role : at.orRole()) {
|
||||
String[] rArr = SaFoxUtil.convertStringToArray(role);
|
||||
// 某一项 role 认证通过,则可以提前退出了,代表通过
|
||||
if (hasRoleAnd(rArr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckSafe ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(SaCheckSafe at) {
|
||||
this.checkSafe(at.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckDisable ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(SaCheckDisable at) {
|
||||
Object loginId = getLoginId();
|
||||
for (String service : at.value()) {
|
||||
this.checkDisableLevel(loginId, service, at.level());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 账号封禁 -------------------
|
||||
@@ -2937,4 +2878,84 @@ public class StpLogic {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------- 过期方法 -------------------
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckLogin ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
@Deprecated
|
||||
public void checkByAnnotation(SaCheckLogin at) {
|
||||
this.checkLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckRole ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
@Deprecated
|
||||
public void checkByAnnotation(SaCheckRole at) {
|
||||
String[] roleArray = at.value();
|
||||
if(at.mode() == SaMode.AND) {
|
||||
this.checkRoleAnd(roleArray);
|
||||
} else {
|
||||
this.checkRoleOr(roleArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckPermission ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
@Deprecated
|
||||
public void checkByAnnotation(SaCheckPermission at) {
|
||||
String[] permissionArray = at.value();
|
||||
try {
|
||||
if(at.mode() == SaMode.AND) {
|
||||
this.checkPermissionAnd(permissionArray);
|
||||
} else {
|
||||
this.checkPermissionOr(permissionArray);
|
||||
}
|
||||
} catch (NotPermissionException e) {
|
||||
// 权限认证校验未通过,再开始角色认证校验
|
||||
for (String role : at.orRole()) {
|
||||
String[] rArr = SaFoxUtil.convertStringToArray(role);
|
||||
// 某一项 role 认证通过,则可以提前退出了,代表通过
|
||||
if (hasRoleAnd(rArr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckSafe ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
@Deprecated
|
||||
public void checkByAnnotation(SaCheckSafe at) {
|
||||
this.checkSafe(at.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解 ( @SaCheckDisable ) 鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
@Deprecated
|
||||
public void checkByAnnotation(SaCheckDisable at) {
|
||||
Object loginId = getLoginId();
|
||||
for (String service : at.value()) {
|
||||
this.checkDisableLevel(loginId, service, at.level());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -224,7 +224,17 @@ public class StpUtil {
|
||||
public static String createLoginSession(Object id, SaLoginModel loginModel) {
|
||||
return stpLogic.createLoginSession(id, loginModel);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定账号 id 的登录会话数据,如果获取不到则创建并返回
|
||||
*
|
||||
* @param id 账号id,建议的类型:(long | int | String)
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public static String getOrCreateLoginSession(Object id) {
|
||||
return stpLogic.getOrCreateLoginSession(id);
|
||||
}
|
||||
|
||||
// --- 注销
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package cn.dev33.satoken.strategy;
|
||||
|
||||
import cn.dev33.satoken.annotation.*;
|
||||
import cn.dev33.satoken.annotation.handler.*;
|
||||
import cn.dev33.satoken.fun.strategy.SaCheckMethodAnnotationFunction;
|
||||
import cn.dev33.satoken.fun.strategy.SaGetAnnotationFunction;
|
||||
import cn.dev33.satoken.fun.strategy.SaIsAnnotationPresentFunction;
|
||||
import cn.dev33.satoken.listener.SaTokenEventCenter;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Sa-Token 注解鉴权相关策略
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public final class SaAnnotationStrategy {
|
||||
|
||||
private SaAnnotationStrategy() {
|
||||
registerDefaultAnnotationHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局单例引用
|
||||
*/
|
||||
public static final SaAnnotationStrategy instance = new SaAnnotationStrategy();
|
||||
|
||||
|
||||
// ----------------------- 所有策略
|
||||
|
||||
/**
|
||||
* 注解处理器集合
|
||||
*/
|
||||
public Map<Class<?>, SaAnnotationHandlerInterface<?>> annotationHandlerMap = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 注册所有默认的注解处理器
|
||||
*/
|
||||
public void registerDefaultAnnotationHandler() {
|
||||
annotationHandlerMap.put(SaIgnore.class, new SaIgnoreHandler());
|
||||
annotationHandlerMap.put(SaCheckLogin.class, new SaCheckLoginHandler());
|
||||
annotationHandlerMap.put(SaCheckRole.class, new SaCheckRoleHandler());
|
||||
annotationHandlerMap.put(SaCheckPermission.class, new SaCheckPermissionHandler());
|
||||
annotationHandlerMap.put(SaCheckSafe.class, new SaCheckSafeHandler());
|
||||
annotationHandlerMap.put(SaCheckDisable.class, new SaCheckDisableHandler());
|
||||
annotationHandlerMap.put(SaCheckHttpBasic.class, new SaCheckHttpBasicHandler());
|
||||
annotationHandlerMap.put(SaCheckHttpDigest.class, new SaCheckHttpDigestHandler());
|
||||
annotationHandlerMap.put(SaCheckOr.class, new SaCheckOrHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个注解处理器
|
||||
*/
|
||||
public void registerAnnotationHandler(SaAnnotationHandlerInterface<?> handler) {
|
||||
annotationHandlerMap.put(handler.getHandlerAnnotationClass(), handler);
|
||||
SaTokenEventCenter.doRegisterAnnotationHandler(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个注解处理器,到首位
|
||||
*/
|
||||
public void registerAnnotationHandlerToFirst(SaAnnotationHandlerInterface<?> handler) {
|
||||
Map<Class<?>, SaAnnotationHandlerInterface<?>> newMap = new LinkedHashMap<>();
|
||||
newMap.put(handler.getHandlerAnnotationClass(), handler);
|
||||
newMap.putAll(annotationHandlerMap);
|
||||
this.annotationHandlerMap = newMap;
|
||||
SaTokenEventCenter.doRegisterAnnotationHandler(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个注解处理器
|
||||
*/
|
||||
public void removeAnnotationHandler(Class<?> cls) {
|
||||
annotationHandlerMap.remove(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一个 [Method] 对象进行注解校验 (注解鉴权内部实现)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public SaCheckMethodAnnotationFunction checkMethodAnnotation = (method) -> {
|
||||
// 遍历所有的注解处理器,检查此 method 是否具有这些指定的注解
|
||||
for (Map.Entry<Class<?>, SaAnnotationHandlerInterface<?>> entry: annotationHandlerMap.entrySet()) {
|
||||
|
||||
// 先校验 Method 所属 Class 上的注解
|
||||
Annotation classTakeAnnotation = instance.getAnnotation.apply(method.getDeclaringClass(), (Class<Annotation>)entry.getKey());
|
||||
if(classTakeAnnotation != null) {
|
||||
entry.getValue().check(classTakeAnnotation, method);
|
||||
}
|
||||
|
||||
// 再校验 Method 上的注解
|
||||
Annotation methodTakeAnnotation = instance.getAnnotation.apply(method, (Class<Annotation>)entry.getKey());
|
||||
if(methodTakeAnnotation != null) {
|
||||
entry.getValue().check(methodTakeAnnotation, method);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 从元素上获取注解
|
||||
*/
|
||||
public SaGetAnnotationFunction getAnnotation = (element, annotationClass)->{
|
||||
// 默认使用jdk的注解处理器
|
||||
return element.getAnnotation(annotationClass);
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断一个 Method 或其所属 Class 是否包含指定注解
|
||||
*/
|
||||
public SaIsAnnotationPresentFunction isAnnotationPresent = (method, annotationClass) -> {
|
||||
return instance.getAnnotation.apply(method, annotationClass) != null ||
|
||||
instance.getAnnotation.apply(method.getDeclaringClass(), annotationClass) != null;
|
||||
};
|
||||
|
||||
}
|
@@ -16,19 +16,14 @@
|
||||
package cn.dev33.satoken.strategy;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.*;
|
||||
import cn.dev33.satoken.exception.RequestPathInvalidException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.fun.strategy.*;
|
||||
import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
|
||||
import cn.dev33.satoken.httpauth.digest.SaHttpDigestUtil;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@@ -133,185 +128,6 @@ public final class SaStrategy {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 对一个 [Method] 对象进行注解校验 (注解鉴权内部实现)
|
||||
*/
|
||||
public SaCheckMethodAnnotationFunction checkMethodAnnotation = (method) -> {
|
||||
|
||||
// 先校验 Method 所属 Class 上的注解
|
||||
instance.checkElementAnnotation.accept(method.getDeclaringClass());
|
||||
|
||||
// 再校验 Method 上的注解
|
||||
instance.checkElementAnnotation.accept(method);
|
||||
};
|
||||
|
||||
/**
|
||||
* 对一个 [元素] 对象进行注解校验 (注解鉴权内部实现)
|
||||
*/
|
||||
public SaCheckElementAnnotationFunction checkElementAnnotation = (element) -> {
|
||||
|
||||
// 校验 @SaCheckLogin 注解
|
||||
SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.instance.getAnnotation.apply(element, SaCheckLogin.class);
|
||||
if(checkLogin != null) {
|
||||
SaManager.getStpLogic(checkLogin.type(), false).checkByAnnotation(checkLogin);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckRole 注解
|
||||
SaCheckRole checkRole = (SaCheckRole) SaStrategy.instance.getAnnotation.apply(element, SaCheckRole.class);
|
||||
if(checkRole != null) {
|
||||
SaManager.getStpLogic(checkRole.type(), false).checkByAnnotation(checkRole);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckPermission 注解
|
||||
SaCheckPermission checkPermission = (SaCheckPermission) SaStrategy.instance.getAnnotation.apply(element, SaCheckPermission.class);
|
||||
if(checkPermission != null) {
|
||||
SaManager.getStpLogic(checkPermission.type(), false).checkByAnnotation(checkPermission);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckSafe 注解
|
||||
SaCheckSafe checkSafe = (SaCheckSafe) SaStrategy.instance.getAnnotation.apply(element, SaCheckSafe.class);
|
||||
if(checkSafe != null) {
|
||||
SaManager.getStpLogic(checkSafe.type(), false).checkByAnnotation(checkSafe);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckDisable 注解
|
||||
SaCheckDisable checkDisable = (SaCheckDisable) SaStrategy.instance.getAnnotation.apply(element, SaCheckDisable.class);
|
||||
if(checkDisable != null) {
|
||||
SaManager.getStpLogic(checkDisable.type(), false).checkByAnnotation(checkDisable);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckHttpBasic 注解
|
||||
SaCheckHttpBasic checkHttpBasic = (SaCheckHttpBasic) SaStrategy.instance.getAnnotation.apply(element, SaCheckHttpBasic.class);
|
||||
if(checkHttpBasic != null) {
|
||||
SaHttpBasicUtil.check(checkHttpBasic.realm(), checkHttpBasic.account());
|
||||
}
|
||||
|
||||
// 校验 @SaCheckHttpDigest 注解
|
||||
SaCheckHttpDigest checkHttpDigest = (SaCheckHttpDigest) SaStrategy.instance.getAnnotation.apply(element, SaCheckHttpDigest.class);
|
||||
if(checkHttpDigest != null) {
|
||||
SaHttpDigestUtil.checkByAnnotation(checkHttpDigest);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckOr 注解
|
||||
SaCheckOr checkOr = (SaCheckOr) SaStrategy.instance.getAnnotation.apply(element, SaCheckOr.class);
|
||||
if(checkOr != null) {
|
||||
SaStrategy.instance.checkOrAnnotation.accept(checkOr);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 对一个 @SaCheckOr 进行注解校验
|
||||
*/
|
||||
public SaCheckOrAnnotationFunction checkOrAnnotation = (at) -> {
|
||||
|
||||
// 记录校验过程中所有的异常
|
||||
List<SaTokenException> errorList = new ArrayList<>();
|
||||
|
||||
// 逐个开始校验 >>>
|
||||
|
||||
// 1、校验注解:@SaCheckLogin
|
||||
SaCheckLogin[] checkLoginArray = at.login();
|
||||
for (SaCheckLogin item : checkLoginArray) {
|
||||
try {
|
||||
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
|
||||
return;
|
||||
} catch (SaTokenException e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 2、校验注解:@SaCheckRole
|
||||
SaCheckRole[] checkRoleArray = at.role();
|
||||
for (SaCheckRole item : checkRoleArray) {
|
||||
try {
|
||||
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
|
||||
return;
|
||||
} catch (SaTokenException e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 3、校验注解:@SaCheckPermission
|
||||
SaCheckPermission[] checkPermissionArray = at.permission();
|
||||
for (SaCheckPermission item : checkPermissionArray) {
|
||||
try {
|
||||
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
|
||||
return;
|
||||
} catch (SaTokenException e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 4、校验注解:@SaCheckSafe
|
||||
SaCheckSafe[] checkSafeArray = at.safe();
|
||||
for (SaCheckSafe item : checkSafeArray) {
|
||||
try {
|
||||
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
|
||||
return;
|
||||
} catch (SaTokenException e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 5、校验注解:@SaCheckDisable
|
||||
SaCheckDisable[] checkDisableArray = at.disable();
|
||||
for (SaCheckDisable item : checkDisableArray) {
|
||||
try {
|
||||
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
|
||||
return;
|
||||
} catch (SaTokenException e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 6、校验注解:@SaCheckBasic
|
||||
SaCheckHttpBasic[] checkHttpBasicArray = at.httpBasic();
|
||||
for (SaCheckHttpBasic item : checkHttpBasicArray) {
|
||||
try {
|
||||
SaHttpBasicUtil.check(item.realm(), item.account());
|
||||
return;
|
||||
} catch (SaTokenException e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 7、校验注解:@SaCheckDigest
|
||||
SaCheckHttpDigest[] checkHttpDigestArray = at.httpDigest();
|
||||
for (SaCheckHttpDigest item : checkHttpDigestArray) {
|
||||
try {
|
||||
SaHttpDigestUtil.checkByAnnotation(item);
|
||||
return;
|
||||
} catch (SaTokenException e) {
|
||||
errorList.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果执行到这里,有两种可能:
|
||||
// 可能 1. SaCheckOr 注解上不包含任何注解校验,此时 errorList 里面一个异常都没有,我们直接跳过即可
|
||||
// 可能 2. 所有注解校验都通过不了,此时 errorList 里面会有多个异常,我们随便抛出一个即可
|
||||
if(errorList.size() == 0) {
|
||||
// return;
|
||||
} else {
|
||||
throw errorList.get(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 从元素上获取注解
|
||||
*/
|
||||
public SaGetAnnotationFunction getAnnotation = (element, annotationClass)->{
|
||||
// 默认使用jdk的注解处理器
|
||||
return element.getAnnotation(annotationClass);
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断一个 Method 或其所属 Class 是否包含指定注解
|
||||
*/
|
||||
public SaIsAnnotationPresentFunction isAnnotationPresent = (method, annotationClass) -> {
|
||||
return instance.getAnnotation.apply(method, annotationClass) != null ||
|
||||
instance.getAnnotation.apply(method.getDeclaringClass(), annotationClass) != null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成唯一式 token 的算法
|
||||
*/
|
||||
@@ -427,62 +243,6 @@ public final class SaStrategy {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一个 [Method] 对象进行注解校验 (注解鉴权内部实现)
|
||||
*
|
||||
* @param checkMethodAnnotation /
|
||||
* @return /
|
||||
*/
|
||||
public SaStrategy setCheckMethodAnnotation(SaCheckMethodAnnotationFunction checkMethodAnnotation) {
|
||||
this.checkMethodAnnotation = checkMethodAnnotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一个 [元素] 对象进行注解校验 (注解鉴权内部实现)
|
||||
*
|
||||
* @param checkElementAnnotation /
|
||||
* @return /
|
||||
*/
|
||||
public SaStrategy setCheckElementAnnotation(SaCheckElementAnnotationFunction checkElementAnnotation) {
|
||||
this.checkElementAnnotation = checkElementAnnotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一个 @SaCheckOr 进行注解校验
|
||||
* <p> 参数 [SaCheckOr 注解的实例]
|
||||
*
|
||||
* @param checkOrAnnotation /
|
||||
* @return /
|
||||
*/
|
||||
public SaStrategy setCheckOrAnnotation(SaCheckOrAnnotationFunction checkOrAnnotation) {
|
||||
this.checkOrAnnotation = checkOrAnnotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从元素上获取注解
|
||||
*
|
||||
* @param getAnnotation /
|
||||
* @return /
|
||||
*/
|
||||
public SaStrategy setGetAnnotation(SaGetAnnotationFunction getAnnotation) {
|
||||
this.getAnnotation = getAnnotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个 Method 或其所属 Class 是否包含指定注解
|
||||
*
|
||||
* @param isAnnotationPresent /
|
||||
* @return /
|
||||
*/
|
||||
public SaStrategy setIsAnnotationPresent(SaIsAnnotationPresentFunction isAnnotationPresent) {
|
||||
this.isAnnotationPresent = isAnnotationPresent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一式 token 的算法
|
||||
*
|
||||
|
@@ -29,7 +29,6 @@ import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Sa-Token 内部工具类
|
||||
@@ -76,6 +75,17 @@ public class SaFoxUtil {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定区间的 int 值
|
||||
*
|
||||
* @param min 最小值(包括)
|
||||
* @param max 最大值(包括)
|
||||
* @return /
|
||||
*/
|
||||
public static int getRandomNumber(int min, int max) {
|
||||
return ThreadLocalRandom.current().nextInt(min, max + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定元素是否为null或者空字符串
|
||||
* @param str 指定元素
|
||||
@@ -96,14 +106,35 @@ public class SaFoxUtil {
|
||||
|
||||
/**
|
||||
* 指定数组是否为null或者空数组
|
||||
* <h3> 该方法已过时,建议使用 isEmptyArray 方法 </h3>
|
||||
* @param <T> /
|
||||
* @param array /
|
||||
* @return /
|
||||
*/
|
||||
@Deprecated
|
||||
public static <T> boolean isEmpty(T[] array) {
|
||||
return isEmptyArray(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定数组是否为null或者空数组
|
||||
* @param <T> /
|
||||
* @param array /
|
||||
* @return /
|
||||
*/
|
||||
public static <T> boolean isEmptyArray(T[] array) {
|
||||
return array == null || array.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定集合是否为null或者空数组
|
||||
* @param list /
|
||||
* @return /
|
||||
*/
|
||||
public static boolean isEmptyList(List<?> list) {
|
||||
return list == null || list.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个对象是否相等
|
||||
* @param a 第一个对象
|
||||
@@ -563,7 +594,7 @@ public class SaFoxUtil {
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String convertListToString(List<?> list) {
|
||||
if(list == null || list.size() == 0) {
|
||||
if(list == null || list.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder str = new StringBuilder();
|
||||
@@ -616,6 +647,15 @@ public class SaFoxUtil {
|
||||
return new ArrayList<>(Arrays.asList(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* String 集合转数组
|
||||
* @param list 集合
|
||||
* @return 数组
|
||||
*/
|
||||
public static String[] toArray(List<String> list) {
|
||||
return list.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public static List<String> logLevelList = Arrays.asList("", "trace", "debug", "info", "warn", "error", "fatal");
|
||||
|
||||
/**
|
||||
@@ -679,4 +719,63 @@ public class SaFoxUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* list1 是否完全包含 list2 中所有元素
|
||||
* @param list1 集合1
|
||||
* @param list2 集合2
|
||||
* @return /
|
||||
*/
|
||||
public static boolean list1ContainList2AllElement(List<String> list1, List<String> list2){
|
||||
if(list2 == null || list2.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if(list1 == null || list1.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (String str : list2) {
|
||||
if(!list1.contains(str)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* list1 是否包含 list2 中任意一个元素
|
||||
* @param list1 集合1
|
||||
* @param list2 集合2
|
||||
* @return /
|
||||
*/
|
||||
public static boolean list1ContainList2AnyElement(List<String> list1, List<String> list2){
|
||||
if(list1 == null || list1.isEmpty() || list2 == null || list2.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (String str : list2) {
|
||||
if(list1.contains(str)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 list1 中剔除 list2 所包含的元素 (克隆副本操作,不影响 list1)
|
||||
* @param list1 集合1
|
||||
* @param list2 集合2
|
||||
* @return /
|
||||
*/
|
||||
public static List<String> list1RemoveByList2(List<String> list1, List<String> list2){
|
||||
if(list1 == null) {
|
||||
return null;
|
||||
}
|
||||
if(list1.isEmpty() || list2 == null || list2.isEmpty()) {
|
||||
return new ArrayList<>(list1);
|
||||
}
|
||||
List<String> listX = new ArrayList<>(list1);
|
||||
for (String str : list2) {
|
||||
listX.remove(str);
|
||||
}
|
||||
return listX;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
@@ -150,7 +152,42 @@ public class SaResult extends LinkedHashMap<String, Object> implements Serializa
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 写入一个 json 字符串, 连缀风格
|
||||
* @param jsonString json 字符串
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaResult setJsonString(String jsonString) {
|
||||
Map<String, Object> map = SaManager.getSaJsonTemplate().parseJsonToMap(jsonString);
|
||||
return setMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除默认属性(code、msg、data), 连缀风格
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaResult removeDefaultFields() {
|
||||
this.remove("code");
|
||||
this.remove("msg");
|
||||
this.remove("data");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除非默认属性(code、msg、data), 连缀风格
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaResult removeNonDefaultFields() {
|
||||
for (String key : this.keySet()) {
|
||||
if("code".equals(key) || "msg".equals(key) || "data".equals(key)) {
|
||||
continue;
|
||||
}
|
||||
this.remove(key);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// ============================ 静态方法快速构建 ==================================
|
||||
|
||||
@@ -180,7 +217,11 @@ public class SaResult extends LinkedHashMap<String, Object> implements Serializa
|
||||
public static SaResult get(int code, String msg, Object data) {
|
||||
return new SaResult(code, msg, data);
|
||||
}
|
||||
|
||||
|
||||
// 构建一个空的
|
||||
public static SaResult empty() {
|
||||
return new SaResult();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
|
@@ -36,7 +36,7 @@ public class SaTokenConsts {
|
||||
/**
|
||||
* Sa-Token 当前版本号
|
||||
*/
|
||||
public static final String VERSION_NO = "v1.38.0";
|
||||
public static final String VERSION_NO = "v1.39.0";
|
||||
|
||||
/**
|
||||
* Sa-Token 开源地址 Gitee
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -73,7 +73,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-bom</artifactId>
|
||||
<version>1.38.0</version>
|
||||
<version>1.39.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -51,7 +51,7 @@
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- @ConfigurationProperties -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@@ -1,10 +1,9 @@
|
||||
package com.pj;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* Sa-Token 示例
|
||||
* @author click33
|
||||
|
@@ -1,10 +1,9 @@
|
||||
package com.pj.cases.test;
|
||||
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
/**
|
||||
* 测试专用 Controller
|
||||
* @author click33
|
||||
@@ -17,14 +16,14 @@ public class TestController {
|
||||
// 测试 浏览器访问: http://localhost:8081/test/test
|
||||
@RequestMapping("test")
|
||||
public SaResult test() {
|
||||
System.out.println("------------进来了");
|
||||
System.out.println("------------进来了");
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
// 测试 浏览器访问: http://localhost:8081/test/test2
|
||||
@RequestMapping("test2")
|
||||
public SaResult test2() {
|
||||
System.out.println("------------进来了");
|
||||
System.out.println("------------进来了");
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
|
@@ -51,25 +51,25 @@ public class SecureController {
|
||||
}
|
||||
|
||||
// RSA加密 ---- http://localhost:8081/secure/rsa
|
||||
@RequestMapping("rsa")
|
||||
public SaResult rsa() {
|
||||
// 定义私钥和公钥
|
||||
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAO+wmt01pwm9lHMdq7A8gkEigk0XKMfjv+4IjAFhWCSiTeP7dtlnceFJbkWxvbc7Qo3fCOpwmfcskwUc3VSgyiJkNJDs9ivPbvlt8IU2bZ+PBDxYxSCJFrgouVOpAr8ar/b6gNuYTi1vt3FkGtSjACFb002/68RKUTye8/tdcVilAgMBAAECgYA1COmrSqTUJeuD8Su9ChZ0HROhxR8T45PjMmbwIz7ilDsR1+E7R4VOKPZKW4Kz2VvnklMhtJqMs4MwXWunvxAaUFzQTTg2Fu/WU8Y9ha14OaWZABfChMZlpkmpJW9arKmI22ZuxCEsFGxghTiJQ3tK8npj5IZq5vk+6mFHQ6aJAQJBAPghz91Dpuj+0bOUfOUmzi22obWCBncAD/0CqCLnJlpfOoa9bOcXSusGuSPuKy5KiGyblHMgKI6bq7gcM2DWrGUCQQD3SkOcmia2s/6i7DUEzMKaB0bkkX4Ela/xrfV+A3GzTPv9bIBamu0VIHznuiZbeNeyw7sVo4/GTItq/zn2QJdBAkEA8xHsVoyXTVeShaDIWJKTFyT5dJ1TR++/udKIcuiNIap34tZdgGPI+EM1yoTduBM7YWlnGwA9urW0mj7F9e9WIQJAFjxqSfmeg40512KP/ed/lCQVXtYqU7U2BfBTg8pBfhLtEcOg4wTNTroGITwe2NjL5HovJ2n2sqkNXEio6Ji0QQJAFLW1Kt80qypMqot+mHhS+0KfdOpaKeMWMSR4Ij5VfE63WzETEeWAMQESxzhavN1WOTb3/p6icgcVbgPQBaWhGg==";
|
||||
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvsJrdNacJvZRzHauwPIJBIoJNFyjH47/uCIwBYVgkok3j+3bZZ3HhSW5Fsb23O0KN3wjqcJn3LJMFHN1UoMoiZDSQ7PYrz275bfCFNm2fjwQ8WMUgiRa4KLlTqQK/Gq/2+oDbmE4tb7dxZBrUowAhW9NNv+vESlE8nvP7XXFYpQIDAQAB";
|
||||
|
||||
// 文本
|
||||
String text = "Sa-Token 一个轻量级java权限认证框架";
|
||||
|
||||
// 使用公钥加密
|
||||
String ciphertext = SaSecureUtil.rsaEncryptByPublic(publicKey, text);
|
||||
System.out.println("公钥加密后:" + ciphertext);
|
||||
|
||||
// 使用私钥解密
|
||||
String text2 = SaSecureUtil.rsaDecryptByPrivate(privateKey, ciphertext);
|
||||
System.out.println("私钥解密后:" + text2);
|
||||
|
||||
return SaResult.ok();
|
||||
}
|
||||
// @RequestMapping("rsa")
|
||||
// public SaResult rsa() {
|
||||
// // 定义私钥和公钥
|
||||
// String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAO+wmt01pwm9lHMdq7A8gkEigk0XKMfjv+4IjAFhWCSiTeP7dtlnceFJbkWxvbc7Qo3fCOpwmfcskwUc3VSgyiJkNJDs9ivPbvlt8IU2bZ+PBDxYxSCJFrgouVOpAr8ar/b6gNuYTi1vt3FkGtSjACFb002/68RKUTye8/tdcVilAgMBAAECgYA1COmrSqTUJeuD8Su9ChZ0HROhxR8T45PjMmbwIz7ilDsR1+E7R4VOKPZKW4Kz2VvnklMhtJqMs4MwXWunvxAaUFzQTTg2Fu/WU8Y9ha14OaWZABfChMZlpkmpJW9arKmI22ZuxCEsFGxghTiJQ3tK8npj5IZq5vk+6mFHQ6aJAQJBAPghz91Dpuj+0bOUfOUmzi22obWCBncAD/0CqCLnJlpfOoa9bOcXSusGuSPuKy5KiGyblHMgKI6bq7gcM2DWrGUCQQD3SkOcmia2s/6i7DUEzMKaB0bkkX4Ela/xrfV+A3GzTPv9bIBamu0VIHznuiZbeNeyw7sVo4/GTItq/zn2QJdBAkEA8xHsVoyXTVeShaDIWJKTFyT5dJ1TR++/udKIcuiNIap34tZdgGPI+EM1yoTduBM7YWlnGwA9urW0mj7F9e9WIQJAFjxqSfmeg40512KP/ed/lCQVXtYqU7U2BfBTg8pBfhLtEcOg4wTNTroGITwe2NjL5HovJ2n2sqkNXEio6Ji0QQJAFLW1Kt80qypMqot+mHhS+0KfdOpaKeMWMSR4Ij5VfE63WzETEeWAMQESxzhavN1WOTb3/p6icgcVbgPQBaWhGg==";
|
||||
// String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvsJrdNacJvZRzHauwPIJBIoJNFyjH47/uCIwBYVgkok3j+3bZZ3HhSW5Fsb23O0KN3wjqcJn3LJMFHN1UoMoiZDSQ7PYrz275bfCFNm2fjwQ8WMUgiRa4KLlTqQK/Gq/2+oDbmE4tb7dxZBrUowAhW9NNv+vESlE8nvP7XXFYpQIDAQAB";
|
||||
//
|
||||
// // 文本
|
||||
// String text = "Sa-Token 一个轻量级java权限认证框架";
|
||||
//
|
||||
// // 使用公钥加密
|
||||
// String ciphertext = SaSecureUtil.rsaEncryptByPublic(publicKey, text);
|
||||
// System.out.println("公钥加密后:" + ciphertext);
|
||||
//
|
||||
// // 使用私钥解密
|
||||
// String text2 = SaSecureUtil.rsaDecryptByPrivate(privateKey, ciphertext);
|
||||
// System.out.println("私钥解密后:" + text2);
|
||||
//
|
||||
// return SaResult.ok();
|
||||
// }
|
||||
|
||||
// Base64 编码 ---- http://localhost:8081/secure/base64
|
||||
@RequestMapping("base64")
|
||||
|
@@ -4,7 +4,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import cn.dev33.satoken.exception.DisableServiceException;
|
||||
import cn.dev33.satoken.exception.NotBasicAuthException;
|
||||
import cn.dev33.satoken.exception.NotHttpBasicAuthException;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
@@ -57,8 +57,8 @@ public class GlobalException {
|
||||
}
|
||||
|
||||
// 拦截:Http Basic 校验失败异常
|
||||
@ExceptionHandler(NotBasicAuthException.class)
|
||||
public SaResult handlerException(NotBasicAuthException e) {
|
||||
@ExceptionHandler(NotHttpBasicAuthException.class)
|
||||
public SaResult handlerException(NotHttpBasicAuthException e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error(e.getMessage());
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import cn.dev33.satoken.filter.SaServletFilter;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.strategy.SaStrategy;
|
||||
import cn.dev33.satoken.strategy.SaAnnotationStrategy;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -32,14 +32,14 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
// 注册 Sa-Token 拦截器打开注解鉴权功能
|
||||
registry.addInterceptor(new SaInterceptor(handle -> {
|
||||
// SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
|
||||
|
||||
|
||||
// 指定一条 match 规则
|
||||
SaRouter
|
||||
.match("/user/**") // 拦截的 path 列表,可以写多个
|
||||
.notMatch("/user/doLogin", "/user/doLogin2") // 排除掉的 path 列表,可以写多个
|
||||
.check(r -> StpUtil.checkLogin()); // 要执行的校验动作,可以写完整的 lambda 表达式
|
||||
.match("/user/**") // 拦截的 path 列表,可以写多个
|
||||
.notMatch("/user/doLogin", "/user/doLogin2") // 排除掉的 path 列表,可以写多个
|
||||
.check(r -> StpUtil.checkLogin()); // 要执行的校验动作,可以写完整的 lambda 表达式
|
||||
|
||||
// 权限校验 -- 不同模块认证不同权限
|
||||
// 权限校验 -- 不同模块认证不同权限
|
||||
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
|
||||
SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
|
||||
SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
|
||||
@@ -49,16 +49,16 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
// 甚至你可以随意的写一个打印语句
|
||||
SaRouter.match("/router/print", r -> System.out.println("----啦啦啦----"));
|
||||
|
||||
// 写一个完整的 lambda
|
||||
// 写一个完整的 lambda
|
||||
SaRouter.match("/router/print2", r -> {
|
||||
System.out.println("----啦啦啦2----");
|
||||
// ... 其它代码
|
||||
// ... 其它代码
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* 相关路由都定义在 com.pj.cases.use.RouterCheckController 中
|
||||
* 相关路由都定义在 com.pj.cases.use.RouterCheckController 中
|
||||
*/
|
||||
|
||||
|
||||
})).addPathPatterns("/**");
|
||||
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
@PostConstruct
|
||||
public void rewriteSaStrategy() {
|
||||
// 重写Sa-Token的注解处理器,增加注解合并功能
|
||||
SaStrategy.instance.getAnnotation = (element, annotationClass) -> {
|
||||
SaAnnotationStrategy.instance.getAnnotation = (element, annotationClass) -> {
|
||||
return AnnotatedElementUtils.getMergedAnnotation(element, annotationClass);
|
||||
};
|
||||
}
|
||||
|
@@ -215,6 +215,16 @@ public class StpUserUtil {
|
||||
return stpLogic.createLoginSession(id, loginModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定账号 id 的登录会话数据,如果获取不到则创建并返回
|
||||
*
|
||||
* @param id 账号id,建议的类型:(long | int | String)
|
||||
* @return 返回会话令牌
|
||||
*/
|
||||
public static String getOrCreateLoginSession(Object id) {
|
||||
return stpLogic.getOrCreateLoginSession(id);
|
||||
}
|
||||
|
||||
// --- 注销
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,33 @@
|
||||
package com.pj.satoken.custom_annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 账号校验:在标注一个方法上时,要求前端必须提交相应的账号密码参数才能访问方法。
|
||||
*
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface CheckAccount {
|
||||
|
||||
/**
|
||||
* 需要校验的账号
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* 需要校验的密码
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String pwd();
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package com.pj.satoken.custom_annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 登录认证(User版):只有登录之后才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface SaUserCheckLogin {
|
||||
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
package com.pj.satoken.custom_annotation;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 权限认证(User版):必须具有指定权限才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
||||
*
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface SaUserCheckPermission {
|
||||
|
||||
/**
|
||||
* 需要校验的权限码
|
||||
* @return 需要校验的权限码
|
||||
*/
|
||||
String [] value() default {};
|
||||
|
||||
/**
|
||||
* 验证模式:AND | OR,默认AND
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
/**
|
||||
* 在权限校验不通过时的次要选择,两者只要其一校验成功即可通过校验
|
||||
*
|
||||
* <p>
|
||||
* 例1:@SaCheckPermission(value="user-add", orRole="admin"),
|
||||
* 代表本次请求只要具有 user-add权限 或 admin角色 其一即可通过校验。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 例2: orRole = {"admin", "manager", "staff"},具有三个角色其一即可。 <br>
|
||||
* 例3: orRole = {"admin, manager, staff"},必须三个角色同时具备。
|
||||
* </p>
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String[] orRole() default {};
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.pj.satoken.custom_annotation;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 角色认证(User版):必须具有指定角色标识才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface SaUserCheckRole {
|
||||
|
||||
/**
|
||||
* 需要校验的角色标识
|
||||
* @return 需要校验的角色标识
|
||||
*/
|
||||
String [] value() default {};
|
||||
|
||||
/**
|
||||
* 验证模式:AND | OR,默认AND
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package com.pj.satoken.custom_annotation;
|
||||
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 二级认证校验(User版):客户端必须完成二级认证之后,才能进入该方法,否则将被抛出异常。
|
||||
*
|
||||
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)。
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface SaUserCheckSafe {
|
||||
|
||||
/**
|
||||
* 要校验的服务
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String value() default SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE;
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package com.pj.satoken.custom_annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import com.pj.satoken.custom_annotation.CheckAccount;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 CheckAccount 的处理器
|
||||
*
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class CheckAccountHandler implements SaAnnotationHandlerInterface<CheckAccount> {
|
||||
|
||||
// 指定这个处理器要处理哪个注解
|
||||
@Override
|
||||
public Class<CheckAccount> getHandlerAnnotationClass() {
|
||||
return CheckAccount.class;
|
||||
}
|
||||
|
||||
// 每次请求校验注解时,会执行的方法
|
||||
@Override
|
||||
public void checkMethod(CheckAccount at, Method method) {
|
||||
// 获取前端请求提交的参数
|
||||
String name = SaHolder.getRequest().getParamNotNull("name");
|
||||
String pwd = SaHolder.getRequest().getParamNotNull("pwd");
|
||||
|
||||
// 与注解中指定的值相比较
|
||||
if(name.equals(at.name()) && pwd.equals(at.pwd()) ) {
|
||||
// 校验通过,什么也不做
|
||||
} else {
|
||||
// 校验不通过,则抛出异常
|
||||
throw new SaTokenException("账号或密码错误,未通过校验");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.pj.satoken.custom_annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.annotation.handler.SaCheckLoginHandler;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
import com.pj.satoken.custom_annotation.SaUserCheckLogin;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaUserCheckLogin 的处理器
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@Component
|
||||
public class SaUserCheckLoginHandler implements SaAnnotationHandlerInterface<SaUserCheckLogin> {
|
||||
|
||||
@Override
|
||||
public Class<SaUserCheckLogin> getHandlerAnnotationClass() {
|
||||
return SaUserCheckLogin.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaUserCheckLogin at, Method method) {
|
||||
SaCheckLoginHandler._checkMethod(StpUserUtil.TYPE);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.pj.satoken.custom_annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.annotation.handler.SaCheckPermissionHandler;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
import com.pj.satoken.custom_annotation.SaUserCheckPermission;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaUserCheckPermission 的处理器
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@Component
|
||||
public class SaUserCheckPermissionHandler implements SaAnnotationHandlerInterface<SaUserCheckPermission> {
|
||||
|
||||
@Override
|
||||
public Class<SaUserCheckPermission> getHandlerAnnotationClass() {
|
||||
return SaUserCheckPermission.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaUserCheckPermission at, Method method) {
|
||||
SaCheckPermissionHandler._checkMethod(StpUserUtil.TYPE, at.value(), at.mode(), at.orRole());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.pj.satoken.custom_annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.annotation.handler.SaCheckRoleHandler;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
import com.pj.satoken.custom_annotation.SaUserCheckRole;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaUserCheckRole 的处理器
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@Component
|
||||
public class SaUserCheckRoleHandler implements SaAnnotationHandlerInterface<SaUserCheckRole> {
|
||||
|
||||
@Override
|
||||
public Class<SaUserCheckRole> getHandlerAnnotationClass() {
|
||||
return SaUserCheckRole.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaUserCheckRole at, Method method) {
|
||||
SaCheckRoleHandler._checkMethod(StpUserUtil.TYPE, at.value(), at.mode());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.pj.satoken.custom_annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.annotation.handler.SaCheckSafeHandler;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
import com.pj.satoken.custom_annotation.SaUserCheckSafe;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaUserCheckPermission 的处理器
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@Component
|
||||
public class SaUserCheckSafeHandler implements SaAnnotationHandlerInterface<SaUserCheckSafe> {
|
||||
|
||||
@Override
|
||||
public Class<SaUserCheckSafe> getHandlerAnnotationClass() {
|
||||
return SaUserCheckSafe.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaUserCheckSafe at, Method method) {
|
||||
SaCheckSafeHandler._checkMethod(StpUserUtil.TYPE, at.value());
|
||||
}
|
||||
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
package com.pj.satoken.at;
|
||||
package com.pj.satoken.merge_annotation;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
|
||||
/**
|
||||
* 登录认证(User版):只有登录之后才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
@@ -1,16 +1,15 @@
|
||||
package com.pj.satoken.at;
|
||||
package com.pj.satoken.merge_annotation;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
|
||||
/**
|
||||
* 权限认证(User版):必须具有指定权限才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
||||
@@ -35,5 +34,23 @@ public @interface SaUserCheckPermission {
|
||||
*/
|
||||
@AliasFor(annotation = SaCheckPermission.class)
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
|
||||
/**
|
||||
* 在权限校验不通过时的次要选择,两者只要其一校验成功即可通过校验
|
||||
*
|
||||
* <p>
|
||||
* 例1:@SaCheckPermission(value="user-add", orRole="admin"),
|
||||
* 代表本次请求只要具有 user-add权限 或 admin角色 其一即可通过校验。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 例2: orRole = {"admin", "manager", "staff"},具有三个角色其一即可。 <br>
|
||||
* 例3: orRole = {"admin, manager, staff"},必须三个角色同时具备。
|
||||
* </p>
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@AliasFor(annotation = SaCheckPermission.class)
|
||||
String[] orRole() default {};
|
||||
|
||||
}
|
@@ -1,16 +1,15 @@
|
||||
package com.pj.satoken.at;
|
||||
package com.pj.satoken.merge_annotation;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
|
||||
/**
|
||||
* 角色认证(User版):必须具有指定角色标识才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
@@ -0,0 +1,31 @@
|
||||
package com.pj.satoken.merge_annotation;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckSafe;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import com.pj.satoken.StpUserUtil;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 二级认证校验(User版):客户端必须完成二级认证之后,才能进入该方法,否则将被抛出异常。
|
||||
*
|
||||
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)。
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@SaCheckSafe(type = StpUserUtil.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface SaUserCheckSafe {
|
||||
|
||||
/**
|
||||
* 要校验的服务
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String value() default SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE;
|
||||
|
||||
}
|
@@ -17,7 +17,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
<dubbo.version>2.7.21</dubbo.version>
|
||||
<nacos.version>1.4.2</nacos.version>
|
||||
</properties>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
<dubbo.version>2.7.21</dubbo.version>
|
||||
<nacos.version>1.4.2</nacos.version>
|
||||
</properties>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
<dubbo.version>3.2.2</dubbo.version>
|
||||
<nacos.version>2.2.2</nacos.version>
|
||||
</properties>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
<dubbo.version>3.2.2</dubbo.version>
|
||||
<nacos.version>2.2.2</nacos.version>
|
||||
</properties>
|
||||
|
@@ -27,7 +27,7 @@
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<lombok.version>1.18.10</lombok.version>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -1,17 +1,17 @@
|
||||
package com.pj.oauth2;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.ejlchina.okhttps.OkHttps;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.pj.utils.SoMap;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.ejlchina.okhttps.OkHttps;
|
||||
import com.pj.utils.SoMap;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Sa-OAuth2 Client端 控制器
|
||||
@@ -21,10 +21,10 @@ import cn.dev33.satoken.util.SaResult;
|
||||
public class SaOAuthClientController {
|
||||
|
||||
// 相关参数配置
|
||||
private String clientId = "1001"; // 应用id
|
||||
private String clientSecret = "aaaa-bbbb-cccc-dddd-eeee"; // 应用秘钥
|
||||
private String serverUrl = "http://sa-oauth-server.com:8001"; // 服务端接口
|
||||
|
||||
private final String clientId = "1001"; // 应用id
|
||||
private final String clientSecret = "aaaa-bbbb-cccc-dddd-eeee"; // 应用秘钥
|
||||
private final String serverUrl = "http://sa-oauth-server.com:8000"; // 服务端接口
|
||||
|
||||
// 进入首页
|
||||
@RequestMapping("/")
|
||||
public Object index(HttpServletRequest request) {
|
||||
@@ -34,7 +34,7 @@ public class SaOAuthClientController {
|
||||
|
||||
// 根据Code码进行登录,获取 Access-Token 和 openid
|
||||
@RequestMapping("/codeLogin")
|
||||
public SaResult codeLogin(String code) {
|
||||
public SaResult codeLogin(String code) throws JsonProcessingException {
|
||||
// 调用Server端接口,获取 Access-Token 以及其他信息
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/token")
|
||||
.addBodyPara("grant_type", "authorization_code")
|
||||
@@ -45,26 +45,25 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
return SaResult.error(so.getString("msg"));
|
||||
}
|
||||
|
||||
// 根据openid获取其对应的userId
|
||||
SoMap data = so.getMap("data");
|
||||
long uid = getUserIdByOpenid(data.getString("openid"));
|
||||
data.set("uid", uid);
|
||||
// 根据openid获取其对应的userId
|
||||
long uid = getUserIdByOpenid(so.getString("openid"));
|
||||
so.set("uid", uid);
|
||||
|
||||
// 返回相关参数
|
||||
StpUtil.login(uid);
|
||||
return SaResult.data(data);
|
||||
return SaResult.data(so);
|
||||
}
|
||||
|
||||
// 根据 Refresh-Token 去刷新 Access-Token
|
||||
@RequestMapping("/refresh")
|
||||
public SaResult refresh(String refreshToken) {
|
||||
public SaResult refresh(String refreshToken) throws JsonProcessingException {
|
||||
// 调用Server端接口,通过 Refresh-Token 刷新出一个新的 Access-Token
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/refresh")
|
||||
.addBodyPara("grant_type", "refresh_token")
|
||||
@@ -75,21 +74,20 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
return SaResult.error(so.getString("msg"));
|
||||
}
|
||||
|
||||
// 返回相关参数 (data=新的Access-Token )
|
||||
SoMap data = so.getMap("data");
|
||||
return SaResult.data(data);
|
||||
// 返回相关参数
|
||||
return SaResult.data(so);
|
||||
}
|
||||
|
||||
// 模式三:密码式-授权登录
|
||||
@RequestMapping("/passwordLogin")
|
||||
public SaResult passwordLogin(String username, String password) {
|
||||
public SaResult passwordLogin(String username, String password) throws JsonProcessingException {
|
||||
// 模式三:密码式-授权登录
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/token")
|
||||
.addBodyPara("grant_type", "password")
|
||||
@@ -101,26 +99,25 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
return SaResult.error(so.getString("msg"));
|
||||
}
|
||||
|
||||
// 根据openid获取其对应的userId
|
||||
SoMap data = so.getMap("data");
|
||||
long uid = getUserIdByOpenid(data.getString("openid"));
|
||||
data.set("uid", uid);
|
||||
// 根据openid获取其对应的userId
|
||||
long uid = getUserIdByOpenid(so.getString("openid"));
|
||||
so.set("uid", uid);
|
||||
|
||||
// 返回相关参数
|
||||
StpUtil.login(uid);
|
||||
return SaResult.data(data);
|
||||
return SaResult.data(so);
|
||||
}
|
||||
|
||||
// 模式四:获取应用的 Client-Token
|
||||
@RequestMapping("/clientToken")
|
||||
public SaResult clientToken() {
|
||||
public SaResult clientToken() throws JsonProcessingException {
|
||||
// 调用Server端接口
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/client_token")
|
||||
.addBodyPara("grant_type", "client_credentials")
|
||||
@@ -130,16 +127,15 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
return SaResult.error(so.getString("msg"));
|
||||
}
|
||||
|
||||
// 返回相关参数 (data=新的Client-Token )
|
||||
SoMap data = so.getMap("data");
|
||||
return SaResult.data(data);
|
||||
// 返回相关参数
|
||||
return SaResult.data(so);
|
||||
}
|
||||
|
||||
// 注销登录
|
||||
@@ -151,7 +147,7 @@ public class SaOAuthClientController {
|
||||
|
||||
// 根据 Access-Token 置换相关的资源: 获取账号昵称、头像、性别等信息
|
||||
@RequestMapping("/getUserinfo")
|
||||
public SaResult getUserinfo(String accessToken) {
|
||||
public SaResult getUserinfo(String accessToken) throws JsonProcessingException {
|
||||
// 调用Server端接口,查询开放的资源
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/userinfo")
|
||||
.addBodyPara("access_token", accessToken)
|
||||
@@ -159,16 +155,15 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
return SaResult.error(so.getString("msg"));
|
||||
}
|
||||
|
||||
// 返回相关参数 (data=获取到的资源 )
|
||||
SoMap data = so.getMap("data");
|
||||
return SaResult.data(data);
|
||||
// 返回相关参数 (data=获取到的资源 )
|
||||
return SaResult.data(so);
|
||||
}
|
||||
|
||||
// 全局异常拦截
|
||||
|
@@ -42,33 +42,33 @@
|
||||
<h3>模式一:授权码(Authorization Code)</h3>
|
||||
<p class="pst">授权码:OAuth2.0标准授权流程,先 (重定向) 获取Code授权码,再 (Rest API) 获取 Access-Token 和 Openid </p>
|
||||
|
||||
<a href="http://sa-oauth-server.com:8001/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/">
|
||||
<a href="http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/">
|
||||
<button>点我开始授权登录(静默授权)</button>
|
||||
</a>
|
||||
<span class="ps">当请求链接不包含scope权限时,将无需用户手动确认,做到静默授权,当然此时我们也只能获取openid</span>
|
||||
<code>http://sa-oauth-server.com:8001/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/</code>
|
||||
<span class="ps">当请求链接不包含 scope 权限,或请求的 scope 近期已授权时,将无需用户手动确认,做到静默授权</span>
|
||||
<code>http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/</code>
|
||||
|
||||
<a href="http://sa-oauth-server.com:8001/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/&scope=userinfo">
|
||||
<a href="http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/&scope=openid,userinfo">
|
||||
<button>授权登录(显式授权)</button>
|
||||
</a>
|
||||
<span class="ps">当请求链接包含具体的scope权限时,将需要用户手动确认,此时我们除了openid以外还可以获取更多的资源</span>
|
||||
<code>http://sa-oauth-server.com:8001/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/&scope=userinfo</code>
|
||||
<span class="ps">当请求链接包含具体的 scope 权限时,将需要用户手动确认,此时 OAuth-Server 会返回更多的数据</span>
|
||||
<code>http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/&scope=openid,userinfo</code>
|
||||
|
||||
<button onclick="refreshToken()">刷新令牌</button>
|
||||
<span class="ps">我们可以拿着 Refresh-Token 去刷新我们的 Access-Token,每次刷新后旧Token将作废</span>
|
||||
<code>http://sa-oauth-server.com:8001/oauth2/refresh?grant_type=refresh_token&client_id={value}&client_secret={value}&refresh_token={value}</code>
|
||||
<code>http://sa-oauth-server.com:8000/oauth2/refresh?grant_type=refresh_token&client_id={value}&client_secret={value}&refresh_token={value}</code>
|
||||
|
||||
<button onclick="getUserinfo()">获取账号信息</button>
|
||||
<span class="ps">使用 Access-Token 置换资源: 获取账号昵称、头像、性别等信息 (Access-Token具备userinfo权限时才可以获取成功) </span>
|
||||
<code>http://sa-oauth-server.com:8001/oauth2/userinfo?access_token={value}</code>
|
||||
<code>http://sa-oauth-server.com:8000/oauth2/userinfo?access_token={value}</code>
|
||||
|
||||
<br>
|
||||
<h3>模式二:隐藏式(Implicit)</h3>
|
||||
<a href="http://sa-oauth-server.com:8001/oauth2/authorize?response_type=token&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/&scope=userinfo">
|
||||
<a href="http://sa-oauth-server.com:8000/oauth2/authorize?response_type=token&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/&scope=userinfo">
|
||||
<button>隐藏式</button>
|
||||
</a>
|
||||
<span class="ps">越过授权码的步骤,直接返回token到前端页面( 格式:http//:domain.com#token=xxxx-xxxx )</span>
|
||||
<code>http://sa-oauth-server.com:8001/oauth2/authorize?response_type=token&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/&scope=userinfo</code>
|
||||
<code>http://sa-oauth-server.com:8000/oauth2/authorize?response_type=token&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/&scope=userinfo</code>
|
||||
|
||||
<br>
|
||||
<h3>模式三:密码式(Password)</h3>
|
||||
@@ -76,18 +76,18 @@
|
||||
账号:<input name="username">
|
||||
密码:<input name="password">
|
||||
<button onclick="passwordLogin()">登录</button>
|
||||
<code>http://sa-oauth-server.com:8001/oauth2/token?grant_type=password&client_id={value}&client_secret={value}&username={value}&password={value}</code>
|
||||
<code>http://sa-oauth-server.com:8000/oauth2/token?grant_type=password&client_id={value}&client_secret={value}&username={value}&password={value}</code>
|
||||
|
||||
<br>
|
||||
<h3>模式四:凭证式(Client Credentials)</h3>
|
||||
<p class="pst">以上三种模式获取的都是用户的 Access-Token,代表用户对第三方应用的授权,在OAuth2.0中还有一种针对 Client级别的授权,
|
||||
即:Client-Token,代表应用自身的资源授权</p>
|
||||
<p class="pst">Client-Token具有延迟作废特性,即:在每次获取最新Client-Token的时候,旧Client-Token不会立即过期,而是作为Past-Token再次
|
||||
<p class="pst">Client-Token具有延迟作废特性,即:在每次获取最新Client-Token的时候,旧Client-Token不会立即过期,而是作为Lower-Client-Token再次
|
||||
储存起来,资源请求方只要携带其中之一便可通过Token校验,这种特性保证了在大量并发请求时不会出现“新旧Token交替造成的授权失效”,
|
||||
保证了服务的高可用</p>
|
||||
|
||||
<button onclick="getClientToken()">获取应用Client-Token</button>
|
||||
<code>http://sa-oauth-server.com:8001/oauth2/client_token?grant_type=client_credentials&client_id={value}&client_secret={value}</code>
|
||||
<code>http://sa-oauth-server.com:8000/oauth2/client_token?grant_type=client_credentials&client_id={value}&client_secret={value}</code>
|
||||
|
||||
<br><br>
|
||||
<span>更多资料请参考 Sa-Token 官方文档地址:</span>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -58,13 +58,20 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 热刷新 -->
|
||||
|
||||
<!-- sa-token-jwt 签发 OIDC id_token 令牌 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-jwt</artifactId>
|
||||
<version>${sa-token.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 热刷新 -->
|
||||
<!--<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
|
||||
<!-- ConfigurationProperties -->
|
||||
<dependency>
|
||||
|
@@ -1,18 +1,20 @@
|
||||
package com.pj;
|
||||
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* 启动:Sa-OAuth2 Server端
|
||||
* @author click33
|
||||
* 启动:Sa-OAuth2 Server端
|
||||
* @author click33
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication
|
||||
public class SaOAuth2ServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaOAuth2ServerApplication.class, args);
|
||||
System.out.println("\nSa-Token-OAuth Server端启动成功");
|
||||
System.out.println("\nSa-Token-OAuth2 Server端启动成功,配置如下:");
|
||||
System.out.println(SaOAuth2Manager.getServerConfig());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,46 @@
|
||||
package com.pj.oauth2;
|
||||
|
||||
import cn.dev33.satoken.oauth2.consts.GrantType;
|
||||
import cn.dev33.satoken.oauth2.data.loader.SaOAuth2DataLoader;
|
||||
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Sa-Token OAuth2:自定义数据加载器
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@Component
|
||||
public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
|
||||
|
||||
// 根据 clientId 获取 Client 信息
|
||||
@Override
|
||||
public SaClientModel getClientModel(String clientId) {
|
||||
// 此为模拟数据,真实环境需要从数据库查询
|
||||
if("1001".equals(clientId)) {
|
||||
return new SaClientModel()
|
||||
.setClientId("1001") // client id
|
||||
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee") // client 秘钥
|
||||
.addAllowRedirectUris("*") // 所有允许授权的 url
|
||||
.addContractScopes("openid", "userid", "userinfo", "oidc") // 所有签约的权限
|
||||
.addAllowGrantTypes( // 所有允许的授权模式
|
||||
GrantType.authorization_code, // 授权码式
|
||||
GrantType.implicit, // 隐式式
|
||||
GrantType.refresh_token, // 刷新令牌
|
||||
GrantType.password, // 密码式
|
||||
GrantType.client_credentials, // 客户端模式
|
||||
"phone_code" // 自定义授权模式 手机号验证码登录
|
||||
)
|
||||
;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 根据 clientId 和 loginId 获取 openid
|
||||
@Override
|
||||
public String getOpenid(String clientId, Object loginId) {
|
||||
// 此处使用框架默认算法生成 openid,真实环境建议改为从数据库查询
|
||||
return SaOAuth2DataLoader.super.getOpenid(clientId, loginId);
|
||||
}
|
||||
|
||||
}
|
@@ -1,92 +1,86 @@
|
||||
package com.pj.oauth2;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import cn.dev33.satoken.oauth2.config.SaOAuth2ServerConfig;
|
||||
import cn.dev33.satoken.oauth2.processor.SaOAuth2ServerProcessor;
|
||||
import cn.dev33.satoken.oauth2.template.SaOAuth2Util;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
|
||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Handle;
|
||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Util;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
/**
|
||||
* Sa-OAuth2 Server端 控制器
|
||||
* Sa-Token-OAuth2 Server端 Controller
|
||||
*
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
public class SaOAuth2ServerController {
|
||||
|
||||
// 处理所有OAuth相关请求
|
||||
// OAuth2-Server 端:处理所有 OAuth2 相关请求
|
||||
@RequestMapping("/oauth2/*")
|
||||
public Object request() {
|
||||
System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl());
|
||||
return SaOAuth2Handle.serverRequest();
|
||||
}
|
||||
|
||||
// Sa-OAuth2 定制化配置
|
||||
@Autowired
|
||||
public void setSaOAuth2Config(SaOAuth2Config cfg) {
|
||||
cfg.
|
||||
// 未登录的视图
|
||||
setNotLoginView(()->{
|
||||
return new ModelAndView("login.html");
|
||||
}).
|
||||
// 登录处理函数
|
||||
setDoLoginHandle((name, pwd) -> {
|
||||
if("sa".equals(name) && "123456".equals(pwd)) {
|
||||
StpUtil.login(10001);
|
||||
return SaResult.ok();
|
||||
}
|
||||
return SaResult.error("账号名或密码错误");
|
||||
}).
|
||||
// 授权确认视图
|
||||
setConfirmView((clientId, scope)->{
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("clientId", clientId);
|
||||
map.put("scope", scope);
|
||||
return new ModelAndView("confirm.html", map);
|
||||
})
|
||||
;
|
||||
return SaOAuth2ServerProcessor.instance.dister();
|
||||
}
|
||||
|
||||
// 全局异常拦截
|
||||
@ExceptionHandler
|
||||
public SaResult handlerException(Exception e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error(e.getMessage());
|
||||
// Sa-Token OAuth2 定制化配置
|
||||
@Autowired
|
||||
public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {
|
||||
// 未登录的视图
|
||||
oauth2Server.notLoginView = ()->{
|
||||
return new ModelAndView("login.html");
|
||||
};
|
||||
|
||||
// 登录处理函数
|
||||
oauth2Server.doLoginHandle = (name, pwd) -> {
|
||||
if("sa".equals(name) && "123456".equals(pwd)) {
|
||||
StpUtil.login(10001);
|
||||
return SaResult.ok();
|
||||
}
|
||||
return SaResult.error("账号名或密码错误");
|
||||
};
|
||||
|
||||
// 授权确认视图
|
||||
oauth2Server.confirmView = (clientId, scopes)->{
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("clientId", clientId);
|
||||
map.put("scope", scopes);
|
||||
return new ModelAndView("confirm.html", map);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------- 开放相关资源接口: Client端根据 Access-Token ,置换相关资源 ------------
|
||||
|
||||
// 获取Userinfo信息:昵称、头像、性别等等
|
||||
// 获取 userinfo 信息:昵称、头像、性别等等
|
||||
@RequestMapping("/oauth2/userinfo")
|
||||
public SaResult userinfo() {
|
||||
// 获取 Access-Token 对应的账号id
|
||||
String accessToken = SaHolder.getRequest().getParamNotNull("access_token");
|
||||
// 获取 Access-Token 对应的账号id
|
||||
String accessToken = SaOAuth2Manager.getDataResolver().readAccessToken(SaHolder.getRequest());
|
||||
Object loginId = SaOAuth2Util.getLoginIdByAccessToken(accessToken);
|
||||
System.out.println("-------- 此Access-Token对应的账号id: " + loginId);
|
||||
|
||||
|
||||
// 校验 Access-Token 是否具有权限: userinfo
|
||||
SaOAuth2Util.checkScope(accessToken, "userinfo");
|
||||
|
||||
SaOAuth2Util.checkAccessTokenScope(accessToken, "userinfo");
|
||||
|
||||
// 模拟账号信息 (真实环境需要查询数据库获取信息)
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("nickname", "shengzhang_");
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
// map.put("userId", loginId); 一般原则下,oauth2-server 不能把 userId 返回给 oauth2-client
|
||||
map.put("nickname", "林小林");
|
||||
map.put("avatar", "http://xxx.com/1.jpg");
|
||||
map.put("age", "18");
|
||||
map.put("sex", "男");
|
||||
map.put("address", "山东省 青岛市 城阳区");
|
||||
return SaResult.data(map);
|
||||
return SaResult.ok().setMap(map);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,39 +0,0 @@
|
||||
package com.pj.oauth2;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Template;
|
||||
import cn.dev33.satoken.oauth2.model.SaClientModel;
|
||||
|
||||
/**
|
||||
* Sa-Token OAuth2.0 整合实现
|
||||
* @author click33
|
||||
*/
|
||||
@Component
|
||||
public class SaOAuth2TemplateImpl extends SaOAuth2Template {
|
||||
|
||||
// 根据 id 获取 Client 信息
|
||||
@Override
|
||||
public SaClientModel getClientModel(String clientId) {
|
||||
// 此为模拟数据,真实环境需要从数据库查询
|
||||
if("1001".equals(clientId)) {
|
||||
return new SaClientModel()
|
||||
.setClientId("1001")
|
||||
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee")
|
||||
.setAllowUrl("*")
|
||||
.setContractScope("userinfo")
|
||||
.setIsAutoMode(true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 根据ClientId 和 LoginId 获取openid
|
||||
@Override
|
||||
public String getOpenid(String clientId, Object loginId) {
|
||||
// 此为模拟数据,真实环境需要从数据库查询
|
||||
return "gr_SwoIN0MC1ewxHX_vfCW3BothWDZMMtx__";
|
||||
}
|
||||
|
||||
// -------------- 其它需要重写的函数
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
//package com.pj.oauth2.custom;
|
||||
//
|
||||
//import cn.dev33.satoken.oauth2.data.model.oidc.IdTokenModel;
|
||||
//import cn.dev33.satoken.oauth2.scope.handler.OidcScopeHandler;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
///**
|
||||
// * 扩展 OIDC 权限处理器,返回更多字段
|
||||
// *
|
||||
// * @author click33
|
||||
// * @since 2024/8/24
|
||||
// */
|
||||
//@Component
|
||||
//public class CustomOidcScopeHandler extends OidcScopeHandler {
|
||||
//
|
||||
// @Override
|
||||
// public IdTokenModel workExtraData(IdTokenModel idToken) {
|
||||
// Object userId = idToken.sub;
|
||||
// System.out.println("----- 为 idToken 追加扩展字段 ----- ");
|
||||
//
|
||||
// idToken.extraData.put("uid", userId); // 用户id
|
||||
// idToken.extraData.put("nickname", "lin_xiao_lin"); // 昵称
|
||||
// idToken.extraData.put("picture", "https://sa-token.cc/logo.png"); // 头像
|
||||
// idToken.extraData.put("email", "456456@xx.com"); // 邮箱
|
||||
// idToken.extraData.put("phone_number", "13144556677"); // 手机号
|
||||
// // 更多字段 ...
|
||||
// // 可参考:https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
||||
//
|
||||
// return idToken;
|
||||
// }
|
||||
//
|
||||
//}
|
@@ -0,0 +1,57 @@
|
||||
//package com.pj.oauth2.custom;
|
||||
//
|
||||
//import cn.dev33.satoken.SaManager;
|
||||
//import cn.dev33.satoken.context.model.SaRequest;
|
||||
//import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
//import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
|
||||
//import cn.dev33.satoken.oauth2.data.model.request.RequestAuthModel;
|
||||
//import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
|
||||
//import cn.dev33.satoken.oauth2.granttype.handler.SaOAuth2GrantTypeHandlerInterface;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import java.util.List;
|
||||
//
|
||||
///**
|
||||
// * 自定义 phone_code 授权模式处理器
|
||||
// *
|
||||
// * @author click33
|
||||
// * @since 2024/8/23
|
||||
// */
|
||||
//@Component
|
||||
//public class PhoneCodeGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterface {
|
||||
//
|
||||
// @Override
|
||||
// public String getHandlerGrantType() {
|
||||
// return "phone_code";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public AccessTokenModel getAccessToken(SaRequest req, String clientId, List<String> scopes) {
|
||||
//
|
||||
// // 获取前端提交的参数
|
||||
// String phone = req.getParamNotNull("phone");
|
||||
// String code = req.getParamNotNull("code");
|
||||
// String realCode = SaManager.getSaTokenDao().get("phone_code:" + phone);
|
||||
//
|
||||
// // 1、校验验证码是否正确
|
||||
// if(!code.equals(realCode)) {
|
||||
// throw new SaOAuth2Exception("验证码错误");
|
||||
// }
|
||||
//
|
||||
// // 2、校验通过,删除验证码
|
||||
// SaManager.getSaTokenDao().delete("phone_code:" + phone);
|
||||
//
|
||||
// // 3、登录
|
||||
// long userId = 10001; // 模拟 userId,真实项目应该根据手机号从数据库查询
|
||||
//
|
||||
// // 4、构建 ra 对象
|
||||
// RequestAuthModel ra = new RequestAuthModel();
|
||||
// ra.clientId = clientId;
|
||||
// ra.loginId = userId;
|
||||
// ra.scopes = scopes;
|
||||
//
|
||||
// // 5、生成 Access-Token
|
||||
// AccessTokenModel at = SaOAuth2Manager.getDataGenerate().generateAccessToken(ra, true);
|
||||
// return at;
|
||||
// }
|
||||
//}
|
@@ -0,0 +1,26 @@
|
||||
//package com.pj.oauth2.custom;
|
||||
//
|
||||
//import cn.dev33.satoken.SaManager;
|
||||
//import cn.dev33.satoken.util.SaFoxUtil;
|
||||
//import cn.dev33.satoken.util.SaResult;
|
||||
//import org.springframework.web.bind.annotation.RequestMapping;
|
||||
//import org.springframework.web.bind.annotation.RestController;
|
||||
//
|
||||
///**
|
||||
// * 自定义手机登录接口
|
||||
// *
|
||||
// * @author click33
|
||||
// * @since 2024/8/23
|
||||
// */
|
||||
//@RestController
|
||||
//public class PhoneLoginController {
|
||||
//
|
||||
// @RequestMapping("/oauth2/sendPhoneCode")
|
||||
// public SaResult sendCode(String phone) {
|
||||
// String code = SaFoxUtil.getRandomNumber(100000, 999999) + "";
|
||||
// SaManager.getSaTokenDao().set("phone_code:" + phone, code, 60 * 5);
|
||||
// System.out.println("手机号:" + phone + ",验证码:" + code + ",已发送成功");
|
||||
// return SaResult.ok("验证码发送成功");
|
||||
// }
|
||||
//
|
||||
//}
|
@@ -0,0 +1,41 @@
|
||||
//package com.pj.oauth2.custom;
|
||||
//
|
||||
//import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
|
||||
//import cn.dev33.satoken.oauth2.data.model.ClientTokenModel;
|
||||
//import cn.dev33.satoken.oauth2.scope.handler.SaOAuth2ScopeHandlerInterface;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import java.util.LinkedHashMap;
|
||||
//import java.util.Map;
|
||||
//
|
||||
///**
|
||||
// * @author click33
|
||||
// * @since 2024/8/20
|
||||
// */
|
||||
//@Component
|
||||
//public class UserinfoScopeHandler implements SaOAuth2ScopeHandlerInterface {
|
||||
//
|
||||
// @Override
|
||||
// public String getHandlerScope() {
|
||||
// return "userinfo";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void workAccessToken(AccessTokenModel at) {
|
||||
// System.out.println("--------- userinfo 权限,加工 AccessTokenModel --------- ");
|
||||
// // 模拟账号信息 (真实环境需要查询数据库获取信息)
|
||||
// Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
// map.put("userId", "10008");
|
||||
// map.put("nickname", "shengzhang_");
|
||||
// map.put("avatar", "http://xxx.com/1.jpg");
|
||||
// map.put("age", "18");
|
||||
// map.put("sex", "男");
|
||||
// map.put("address", "山东省 青岛市 城阳区");
|
||||
// at.extraData.put("userinfo", map);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void workClientToken(ClientTokenModel ct) {
|
||||
// }
|
||||
//
|
||||
//}
|
@@ -0,0 +1,22 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* 全局异常处理
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
// 全局异常拦截
|
||||
@ExceptionHandler
|
||||
public SaResult handlerException(Exception e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
|
||||
/**
|
||||
* [Sa-Token 权限认证] 配置类
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 注册 Sa-Token 拦截器打开注解鉴权功能
|
||||
*/
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册 Sa-Token 拦截器打开注解鉴权功能
|
||||
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
package com.pj.test;
|
||||
|
||||
import cn.dev33.satoken.oauth2.annotation.SaCheckAccessToken;
|
||||
import cn.dev33.satoken.oauth2.annotation.SaCheckClientIdSecret;
|
||||
import cn.dev33.satoken.oauth2.annotation.SaCheckClientToken;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* OAuth2 相关注解测试 Controller
|
||||
*
|
||||
* @author click33
|
||||
* @since 2024/8/25
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
public class TestController {
|
||||
|
||||
// 测试:携带有效的 access_token 才可以进入请求
|
||||
// 你可以在请求参数中携带 access_token 参数,或者从请求头以 Authorization: bearer xxx 的形式携带
|
||||
@SaCheckAccessToken
|
||||
@RequestMapping("/checkAccessToken")
|
||||
public SaResult checkAccessToken() {
|
||||
return SaResult.ok("访问成功");
|
||||
}
|
||||
|
||||
// 测试:携带有效的 access_token ,并且具备指定 scope 才可以进入请求
|
||||
@SaCheckAccessToken(scope = "userinfo")
|
||||
@RequestMapping("/checkAccessTokenScope")
|
||||
public SaResult checkAccessTokenScope() {
|
||||
return SaResult.ok("访问成功");
|
||||
}
|
||||
|
||||
// 测试:携带有效的 access_token ,并且具备指定 scope 列表才可以进入请求
|
||||
@SaCheckAccessToken(scope = {"openid", "userinfo"})
|
||||
@RequestMapping("/checkAccessTokenScopeList")
|
||||
public SaResult checkAccessTokenScopeList() {
|
||||
return SaResult.ok("访问成功");
|
||||
}
|
||||
|
||||
// 测试:携带有效的 client_token 才可以进入请求
|
||||
// 你可以在请求参数中携带 client_token 参数,或者从请求头以 Authorization: bearer xxx 的形式携带
|
||||
@SaCheckClientToken
|
||||
@RequestMapping("/checkClientToken")
|
||||
public SaResult checkClientToken() {
|
||||
return SaResult.ok("访问成功");
|
||||
}
|
||||
|
||||
// 测试:携带有效的 client_token ,并且具备指定 scope 才可以进入请求
|
||||
@SaCheckClientToken(scope = "userinfo")
|
||||
@RequestMapping("/checkClientTokenScope")
|
||||
public SaResult checkClientTokenScope() {
|
||||
return SaResult.ok("访问成功");
|
||||
}
|
||||
|
||||
// 测试:携带有效的 client_token ,并且具备指定 scope 列表才可以进入请求
|
||||
@SaCheckClientToken(scope = {"openid", "userinfo"})
|
||||
@RequestMapping("/checkClientTokenScopeList")
|
||||
public SaResult checkClientTokenScopeList() {
|
||||
return SaResult.ok("访问成功");
|
||||
}
|
||||
|
||||
// 测试:携带有效的 client_id 和 client_secret 信息,才可以进入请求
|
||||
// 你可以在请求参数中携带 client_id 和 client_secret 参数,或者从请求头以 Authorization: Basic base64(client_id:client_secret) 的形式携带
|
||||
@SaCheckClientIdSecret
|
||||
@RequestMapping("/checkClientIdSecret")
|
||||
public SaResult checkClientIdSecret() {
|
||||
return SaResult.ok("访问成功");
|
||||
}
|
||||
|
||||
}
|
@@ -1,19 +1,31 @@
|
||||
server:
|
||||
port: 8001
|
||||
server:
|
||||
port: 8000
|
||||
|
||||
# sa-token配置
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
token-name: satoken-server
|
||||
# OAuth2.0 配置
|
||||
oauth2:
|
||||
is-code: true
|
||||
is-implicit: true
|
||||
is-password: true
|
||||
is-client: true
|
||||
|
||||
spring:
|
||||
# redis配置
|
||||
sa-token:
|
||||
# token名称 (同时也是 Cookie 名称)
|
||||
token-name: satoken
|
||||
# 是否打印操作日志
|
||||
is-log: true
|
||||
# jwt 秘钥
|
||||
jwt-secret-key: saxsaxsaxsax
|
||||
# OAuth2.0 配置
|
||||
oauth2-server:
|
||||
# 是否全局开启授权码模式
|
||||
enable-authorization-code: true
|
||||
# 是否全局开启 Implicit 模式
|
||||
enable-implicit: true
|
||||
# 是否全局开启密码模式
|
||||
enable-password: true
|
||||
# 是否全局开启客户端模式
|
||||
enable-client-credentials: true
|
||||
# 定义哪些 scope 是高级权限,多个用逗号隔开
|
||||
# higher-scope: openid,userid
|
||||
# 定义哪些 scope 是低级权限,多个用逗号隔开
|
||||
# lower-scope: userinfo
|
||||
|
||||
spring:
|
||||
# redis配置
|
||||
redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
database: 1
|
||||
@@ -22,7 +34,7 @@ spring:
|
||||
# Redis服务器连接端口
|
||||
port: 6379
|
||||
# Redis服务器连接密码(默认为空)
|
||||
# password:
|
||||
# password:
|
||||
# 连接超时时间(毫秒)
|
||||
timeout: 1000ms
|
||||
lettuce:
|
||||
@@ -35,6 +47,5 @@ spring:
|
||||
max-idle: 10
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -33,20 +33,31 @@
|
||||
console.log('-----------');
|
||||
$.ajax({
|
||||
url: '/oauth2/doConfirm',
|
||||
method: "POST",
|
||||
data: {
|
||||
client_id: getParam('client_id'),
|
||||
scope: getParam('scope')
|
||||
scope: getParam('scope'),
|
||||
// 以下四个参数必须一起出现
|
||||
build_redirect_uri: true,
|
||||
response_type: getParam('response_type'),
|
||||
redirect_uri: getParam('redirect_uri'),
|
||||
state: getParam('state'),
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if(res.code == 200) {
|
||||
console.log('res:', res);
|
||||
if(res.code === 200) {
|
||||
layer.msg('授权成功!');
|
||||
setTimeout(function() {
|
||||
location.reload(true);
|
||||
if (res.redirect_uri) {
|
||||
location.href = res.redirect_uri;
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
}, 800);
|
||||
} else {
|
||||
// 重定向至授权失败URL
|
||||
layer.alert('授权失败!');
|
||||
layer.alert('授权失败:' + res.msg);
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
</properties>
|
||||
|
@@ -10,13 +10,16 @@
|
||||
<parent>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon-parent</artifactId>
|
||||
<version>2.7.0</version>
|
||||
<version>2.9.1</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<java.version>17</java.version>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.traget>17</maven.compiler.traget>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
</properties>
|
||||
|
@@ -0,0 +1,33 @@
|
||||
package com.pj.satoken.custom_annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 账号校验:在标注一个方法上时,要求前端必须提交相应的账号密码参数才能访问方法。
|
||||
*
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface CheckAccount {
|
||||
|
||||
/**
|
||||
* 需要校验的账号
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* 需要校验的密码
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String pwd();
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package com.pj.satoken.custom_annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import com.pj.satoken.custom_annotation.CheckAccount;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 CheckAccount 的处理器
|
||||
*
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class CheckAccountHandler implements SaAnnotationHandlerInterface<CheckAccount> {
|
||||
|
||||
// 指定这个处理器要处理哪个注解
|
||||
@Override
|
||||
public Class<CheckAccount> getHandlerAnnotationClass() {
|
||||
return CheckAccount.class;
|
||||
}
|
||||
|
||||
// 每次请求校验注解时,会执行的方法
|
||||
@Override
|
||||
public void checkMethod(CheckAccount at, Method method) {
|
||||
// 获取前端请求提交的参数
|
||||
String name = SaHolder.getRequest().getParamNotNull("name");
|
||||
String pwd = SaHolder.getRequest().getParamNotNull("pwd");
|
||||
|
||||
// 与注解中指定的值相比较
|
||||
if(name.equals(at.name()) && pwd.equals(at.pwd()) ) {
|
||||
// 校验通过,什么也不做
|
||||
} else {
|
||||
// 校验不通过,则抛出异常
|
||||
throw new SaTokenException("账号或密码错误,未通过校验");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -27,7 +27,7 @@
|
||||
<!--<spring.version>4.2.5.RELEASE</spring.version>-->
|
||||
<spring.version>5.3.7</spring.version>
|
||||
<jackson.version>2.16.1</jackson.version>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
<solon.version>2.7.0</solon.version>
|
||||
</properties>
|
||||
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -50,7 +50,7 @@ var pData = {
|
||||
sa.ajax("/sso/getRedirectUrl", pData, function(res) {
|
||||
if(res.code == 200) {
|
||||
// 已登录,并且redirect地址有效,开始跳转
|
||||
location.href = decodeURIComponent(res.data);
|
||||
location.href = res.data;
|
||||
} else if(res.code == 401) {
|
||||
console.log('未登录');
|
||||
} else {
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.38.0</sa-token.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user