mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-10-21 19:17:25 +08:00
新增sa-token-oauth2 注解鉴权
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.oauth2.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Access-Token 校验:指定请求中必须包含有效的 access_token ,并且包含指定的 scope
|
||||
*
|
||||
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD,ElementType.TYPE})
|
||||
public @interface SaCheckAccessToken {
|
||||
|
||||
/**
|
||||
* 需要校验的 scope [ 数组 ]
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String [] scope() default {};
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.oauth2.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* ClientSecret 校验:指定请求中必须包含有效的 client_id 和 client_secret 信息
|
||||
*
|
||||
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD,ElementType.TYPE})
|
||||
public @interface SaCheckClientIdSecret {
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.oauth2.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Client-Token 校验:指定请求中必须包含有效的 client_token ,并且包含指定的 scope
|
||||
*
|
||||
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD,ElementType.TYPE})
|
||||
public @interface SaCheckClientToken {
|
||||
|
||||
/**
|
||||
* 需要校验的 scope [ 数组 ]
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String [] scope() default {};
|
||||
|
||||
}
|
@@ -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.oauth2.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import cn.dev33.satoken.oauth2.annotation.SaCheckAccessToken;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckAccessToken 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaCheckAccessTokenHandler implements SaAnnotationHandlerInterface<SaCheckAccessToken> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckAccessToken> getHandlerAnnotationClass() {
|
||||
return SaCheckAccessToken.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckAccessToken at, Method method) {
|
||||
_checkMethod(at.scope());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String[] scope) {
|
||||
String accessToken = SaOAuth2Manager.getDataResolver().readAccessToken(SaHolder.getRequest());
|
||||
SaOAuth2Manager.getTemplate().checkAccessTokenScope(accessToken, scope);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.oauth2.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.oauth2.annotation.SaCheckClientIdSecret;
|
||||
import cn.dev33.satoken.oauth2.processor.SaOAuth2ServerProcessor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckClientSecret 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaCheckClientIdSecretHandler implements SaAnnotationHandlerInterface<SaCheckClientIdSecret> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckClientIdSecret> getHandlerAnnotationClass() {
|
||||
return SaCheckClientIdSecret.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckClientIdSecret at, Method method) {
|
||||
_checkMethod();
|
||||
}
|
||||
|
||||
public static void _checkMethod() {
|
||||
SaOAuth2ServerProcessor.instance.checkCurrClientSecret();
|
||||
}
|
||||
|
||||
}
|
@@ -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.oauth2.annotation.handler;
|
||||
|
||||
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import cn.dev33.satoken.oauth2.annotation.SaCheckClientToken;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 注解 SaCheckAccessToken 的处理器
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaCheckClientTokenHandler implements SaAnnotationHandlerInterface<SaCheckClientToken> {
|
||||
|
||||
@Override
|
||||
public Class<SaCheckClientToken> getHandlerAnnotationClass() {
|
||||
return SaCheckClientToken.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMethod(SaCheckClientToken at, Method method) {
|
||||
_checkMethod(at.scope());
|
||||
}
|
||||
|
||||
public static void _checkMethod(String[] scope) {
|
||||
String clientToken = SaOAuth2Manager.getDataResolver().readClientToken(SaHolder.getRequest());
|
||||
SaOAuth2Manager.getTemplate().checkClientTokenScope(clientToken, scope);
|
||||
}
|
||||
|
||||
}
|
@@ -52,6 +52,7 @@ public class SaOAuth2Consts {
|
||||
public static String token = "token";
|
||||
public static String access_token = "access_token";
|
||||
public static String refresh_token = "refresh_token";
|
||||
public static String client_token = "client_token";
|
||||
public static String grant_type = "grant_type";
|
||||
public static String username = "username";
|
||||
public static String password = "password";
|
||||
|
@@ -50,6 +50,14 @@ public interface SaOAuth2DataResolver {
|
||||
*/
|
||||
String readAccessToken(SaRequest request);
|
||||
|
||||
/**
|
||||
* 数据读取:从请求对象中读取 ClientToken
|
||||
*
|
||||
* @param request /
|
||||
* @return /
|
||||
*/
|
||||
String readClientToken(SaRequest request);
|
||||
|
||||
/**
|
||||
* 数据读取:从请求对象中构建 RequestAuthModel
|
||||
* @param req SaRequest对象
|
||||
|
@@ -98,6 +98,33 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据读取:从请求对象中读取 ClientToken
|
||||
*/
|
||||
@Override
|
||||
public String readClientToken(SaRequest request) {
|
||||
// 优先从请求参数中获取
|
||||
String clientToken = request.getParam(SaOAuth2Consts.Param.client_token);
|
||||
if(SaFoxUtil.isNotEmpty(clientToken)) {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
// 如果请求参数中没有提供 client_token 参数,则尝试从 Authorization 中获取
|
||||
String authorizationValue = request.getHeader(SaOAuth2Consts.Param.Authorization);
|
||||
if(SaFoxUtil.isEmpty(authorizationValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 判断前缀,裁剪
|
||||
String prefix = TokenType.Bearer + " ";
|
||||
if(authorizationValue.startsWith(prefix)) {
|
||||
return authorizationValue.substring(prefix.length());
|
||||
}
|
||||
|
||||
// 前缀不符合,返回 null
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据读取:从请求对象中构建 RequestAuthModel
|
||||
*/
|
||||
|
@@ -37,7 +37,6 @@ import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
|
||||
import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy;
|
||||
import cn.dev33.satoken.oauth2.template.SaOAuth2Template;
|
||||
import cn.dev33.satoken.router.SaHttpMethod;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
import java.util.List;
|
||||
@@ -332,6 +331,17 @@ public class SaOAuth2ServerProcessor {
|
||||
return oauth2Template.checkClientModel(clientIdAndSecret.clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验当前请求中提交的 clientId 和 clientSecret 是否正确,如果正确则返回 SaClientModel 对象
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public SaClientModel checkCurrClientSecret() {
|
||||
SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
|
||||
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(SaHolder.getRequest());
|
||||
return oauth2Template.checkClientSecret(clientIdAndSecret.clientId, clientIdAndSecret.clientSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 authorize 路由的 ResponseType 参数
|
||||
*/
|
||||
|
@@ -415,12 +415,12 @@ public class SaOAuth2Template {
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public void checkAccessTokenScope(String accessToken, String... scopes) {
|
||||
AccessTokenModel at = checkAccessToken(accessToken);
|
||||
if(SaFoxUtil.isEmptyArray(scopes)) {
|
||||
return;
|
||||
}
|
||||
ClientTokenModel ct = checkClientToken(accessToken);
|
||||
for (String scope : scopes) {
|
||||
if(! ct.scopes.contains(scope)) {
|
||||
if(! at.scopes.contains(scope)) {
|
||||
throw new SaOAuth2AccessTokenScopeException("该 access_token 不具备 scope:" + scope)
|
||||
.setAccessToken(accessToken)
|
||||
.setScope(scope)
|
||||
@@ -461,11 +461,6 @@ public class SaOAuth2Template {
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
dao.deleteAccessToken(accessToken);
|
||||
dao.deleteAccessTokenIndex(at.clientId, at.loginId);
|
||||
|
||||
// 删对应的 rt、索引
|
||||
// String rtValue = dao.getRefreshTokenValue(at.clientId, at.loginId);
|
||||
// dao.deleteRefreshToken(rtValue);
|
||||
// dao.deleteRefreshTokenIndex(at.clientId, at.loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -586,10 +581,10 @@ public class SaOAuth2Template {
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public void checkClientTokenScope(String clientToken, String... scopes) {
|
||||
ClientTokenModel ct = checkClientToken(clientToken);
|
||||
if(SaFoxUtil.isEmptyArray(scopes)) {
|
||||
return;
|
||||
}
|
||||
ClientTokenModel ct = checkClientToken(clientToken);
|
||||
for (String scope : scopes) {
|
||||
if(! ct.scopes.contains(scope)) {
|
||||
throw new SaOAuth2ClientTokenScopeException("该 client_token 不具备 scope:" + scope)
|
||||
|
Reference in New Issue
Block a user