mirror of
https://github.com/hs-web/hsweb-framework.git
synced 2026-06-08 17:03:39 +08:00
增加部分实现
This commit is contained in:
@@ -49,9 +49,11 @@ public final class AuthenticationHolder {
|
||||
|
||||
private static final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
private static Optional<Authentication> get(Function<AuthenticationSupplier, Authentication> function) {
|
||||
private static Optional<Authentication> get(Function<AuthenticationSupplier, Optional<Authentication>> function) {
|
||||
|
||||
return Flux.fromStream(suppliers.stream().map(function))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.reduceWith(CompositeAuthentication::new, CompositeAuthentication::merge)
|
||||
.filter(CompositeAuthentication::isNotEmpty)
|
||||
.map(Authentication.class::cast)
|
||||
|
||||
@@ -18,10 +18,7 @@
|
||||
|
||||
package org.hswebframework.web.authorization;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 授权信息管理器,用于获取用户授权和同步授权信息
|
||||
@@ -37,7 +34,7 @@ public interface AuthenticationManager {
|
||||
* @param request 授权请求
|
||||
* @return 授权成功则返回用户权限信息
|
||||
*/
|
||||
Mono<Authentication> authenticate(Mono<AuthenticationRequest> request);
|
||||
Authentication authenticate(AuthenticationRequest request);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取权限信息
|
||||
@@ -45,7 +42,7 @@ public interface AuthenticationManager {
|
||||
* @param userId 用户ID
|
||||
* @return 权限信息
|
||||
*/
|
||||
Mono<Authentication> getByUserId(String userId);
|
||||
Optional<Authentication> getByUserId(String userId);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.hswebframework.web.authorization;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@@ -27,6 +28,7 @@ import java.util.function.Supplier;
|
||||
* @see Authentication
|
||||
* @see ReactiveAuthenticationHolder
|
||||
*/
|
||||
public interface AuthenticationSupplier extends Supplier<Authentication> {
|
||||
Authentication get(String userId);
|
||||
public interface AuthenticationSupplier extends Supplier<Optional<Authentication>> {
|
||||
|
||||
Optional<Authentication> get(String userId);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import reactor.core.publisher.Mono;
|
||||
* @author zhouhao
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface AuthenticationInitializeService {
|
||||
public interface ReactiveAuthenticationInitializeService {
|
||||
/**
|
||||
* 根据用户ID初始化权限信息
|
||||
*
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2019 http://www.hswebframework.org
|
||||
*
|
||||
* 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 org.hswebframework.web.authorization;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 授权信息管理器,用于获取用户授权和同步授权信息
|
||||
*
|
||||
* @author zhouhao
|
||||
* @see 3.0
|
||||
*/
|
||||
public interface ReactiveAuthenticationManager {
|
||||
|
||||
/**
|
||||
* 进行授权操作
|
||||
*
|
||||
* @param request 授权请求
|
||||
* @return 授权成功则返回用户权限信息
|
||||
*/
|
||||
Mono<Authentication> authenticate(Mono<AuthenticationRequest> request);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取权限信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 权限信息
|
||||
*/
|
||||
Mono<Authentication> getByUserId(String userId);
|
||||
|
||||
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import java.io.Serializable;
|
||||
* @author zhouhao
|
||||
* @see CustomDataAccessConfig
|
||||
* @see OwnCreatedDataAccessConfig
|
||||
* @see ScriptDataAccessConfig
|
||||
*/
|
||||
public interface DataAccessConfig extends Serializable {
|
||||
|
||||
@@ -72,19 +71,12 @@ public interface DataAccessConfig extends Serializable {
|
||||
String FIELD_SCOPE = "FIELD_SCOPE";
|
||||
|
||||
/**
|
||||
* 字段过滤,黑名单
|
||||
* 禁止操作字段
|
||||
*
|
||||
* @see FieldFilterDataAccessConfig#getType()
|
||||
*/
|
||||
String DENY_FIELDS = "DENY_FIELDS";
|
||||
|
||||
/**
|
||||
* 自定义脚本方式
|
||||
*
|
||||
* @see ScriptDataAccessConfig#getType()
|
||||
*/
|
||||
String SCRIPT = "SCRIPT";
|
||||
|
||||
/**
|
||||
* 自定义控制器
|
||||
*
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.hswebframework.web.authorization.access;
|
||||
|
||||
/**
|
||||
* 通过脚本来控制数据操作权限.脚本可以在前端设置角色的时候进行编辑
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
public interface ScriptDataAccessConfig extends DataAccessConfig {
|
||||
@Override
|
||||
default String getType() {
|
||||
return DefaultType.SCRIPT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 脚本语言: javascript(js),groovy
|
||||
*
|
||||
* @return 语言
|
||||
*/
|
||||
String getScriptLanguage();
|
||||
|
||||
/**
|
||||
* 脚本内容,在进行验证的时候会执行脚本
|
||||
*
|
||||
* @return 脚本
|
||||
*/
|
||||
String getScript();
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package org.hswebframework.web.authorization.builder;
|
||||
|
||||
import org.hswebframework.web.authorization.access.DataAccessConfig;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhouhao
|
||||
@@ -9,5 +11,7 @@ import org.hswebframework.web.authorization.access.DataAccessConfig;
|
||||
public interface DataAccessConfigBuilder {
|
||||
DataAccessConfigBuilder fromJson(String json);
|
||||
|
||||
DataAccessConfigBuilder fromMap(Map<String,Object> json);
|
||||
|
||||
DataAccessConfig build();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package org.hswebframework.web.authorization.simple;
|
||||
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationHolder;
|
||||
import org.hswebframework.web.authorization.AuthenticationManager;
|
||||
import org.hswebframework.web.authorization.*;
|
||||
import org.hswebframework.web.authorization.builder.AuthenticationBuilderFactory;
|
||||
import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory;
|
||||
import org.hswebframework.web.authorization.simple.builder.DataAccessConfigConvert;
|
||||
import org.hswebframework.web.authorization.simple.builder.SimpleAuthenticationBuilderFactory;
|
||||
import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory;
|
||||
import org.hswebframework.web.authorization.token.DefaultUserTokenManager;
|
||||
import org.hswebframework.web.authorization.token.UserTokenAuthenticationSupplier;
|
||||
import org.hswebframework.web.authorization.token.UserTokenReactiveAuthenticationSupplier;
|
||||
import org.hswebframework.web.authorization.token.UserTokenManager;
|
||||
import org.hswebframework.web.authorization.twofactor.TwoFactorValidatorManager;
|
||||
@@ -40,14 +39,23 @@ public class DefaultAuthorizationAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(AuthenticationManager.class)
|
||||
public UserTokenReactiveAuthenticationSupplier userTokenAuthenticationSupplier(UserTokenManager userTokenManager,
|
||||
AuthenticationManager authenticationManager) {
|
||||
@ConditionalOnBean(ReactiveAuthenticationManager.class)
|
||||
public UserTokenReactiveAuthenticationSupplier userTokenReactiveAuthenticationSupplier(UserTokenManager userTokenManager,
|
||||
ReactiveAuthenticationManager authenticationManager) {
|
||||
UserTokenReactiveAuthenticationSupplier supplier = new UserTokenReactiveAuthenticationSupplier(userTokenManager, authenticationManager);
|
||||
ReactiveAuthenticationHolder.addSupplier(supplier);
|
||||
return supplier;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(AuthenticationManager.class)
|
||||
public UserTokenAuthenticationSupplier userTokenAuthenticationSupplier(UserTokenManager userTokenManager,
|
||||
AuthenticationManager authenticationManager) {
|
||||
UserTokenAuthenticationSupplier supplier = new UserTokenAuthenticationSupplier(userTokenManager, authenticationManager);
|
||||
AuthenticationHolder.addSupplier(supplier);
|
||||
return supplier;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(DataAccessConfigBuilderFactory.class)
|
||||
@ConfigurationProperties(prefix = "hsweb.authorization.data-access", ignoreInvalidFields = true)
|
||||
|
||||
@@ -58,6 +58,9 @@ public class SimpleAuthentication implements Authentication {
|
||||
|
||||
@Override
|
||||
public List<Permission> getPermissions() {
|
||||
if(permissions==null){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ArrayList<>(permissions);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package org.hswebframework.web.authorization.simple;
|
||||
|
||||
import lombok.*;
|
||||
import org.hswebframework.web.authorization.access.ScriptDataAccessConfig;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SimpleScriptDataAccessConfig extends AbstractDataAccessConfig implements ScriptDataAccessConfig {
|
||||
|
||||
private static final long serialVersionUID = 2667127339980983720L;
|
||||
|
||||
private String script;
|
||||
|
||||
private String scriptLanguage;
|
||||
}
|
||||
@@ -5,17 +5,21 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import org.hswebframework.web.authorization.access.DataAccessConfig;
|
||||
import org.hswebframework.web.authorization.builder.DataAccessConfigBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class SimpleDataAccessConfigBuilder implements DataAccessConfigBuilder {
|
||||
private String json;
|
||||
|
||||
private List<DataAccessConfigConvert> converts;
|
||||
|
||||
private Map<String, Object> config = new HashMap<>();
|
||||
|
||||
|
||||
public SimpleDataAccessConfigBuilder(List<DataAccessConfigConvert> converts) {
|
||||
Objects.requireNonNull(converts);
|
||||
this.converts = converts;
|
||||
@@ -23,14 +27,20 @@ public class SimpleDataAccessConfigBuilder implements DataAccessConfigBuilder {
|
||||
|
||||
@Override
|
||||
public DataAccessConfigBuilder fromJson(String json) {
|
||||
this.json = json;
|
||||
config.putAll(JSON.parseObject(json));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataAccessConfigBuilder fromMap(Map<String, Object> map) {
|
||||
config.putAll(map);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataAccessConfig build() {
|
||||
Objects.requireNonNull(json);
|
||||
JSONObject jsonObject = JSON.parseObject(json);
|
||||
Objects.requireNonNull(config);
|
||||
JSONObject jsonObject = new JSONObject(config);
|
||||
|
||||
String type = jsonObject.getString("type");
|
||||
String action = jsonObject.getString("action");
|
||||
@@ -40,7 +50,7 @@ public class SimpleDataAccessConfigBuilder implements DataAccessConfigBuilder {
|
||||
Objects.requireNonNull(action);
|
||||
|
||||
if (config == null) {
|
||||
config = json;
|
||||
config = jsonObject.toJSONString();
|
||||
}
|
||||
String finalConfig = config;
|
||||
|
||||
|
||||
@@ -81,9 +81,6 @@ public class SimpleDataAccessConfigBuilderFactory implements DataAccessConfigBui
|
||||
converts.add(createConfig(OWN_CREATED, (action, config) -> new SimpleOwnCreatedDataAccessConfig(action)));
|
||||
}
|
||||
|
||||
if (defaultSupportConvert.contains(SCRIPT)) {
|
||||
converts.add(createJsonConfig(SCRIPT, SimpleScriptDataAccessConfig.class));
|
||||
}
|
||||
|
||||
if (defaultSupportConvert.contains(CUSTOM)) {
|
||||
converts.add(createConfig(CUSTOM, (action, config) -> new SimpleCustomDataAccessConfigConfig(config)));
|
||||
|
||||
@@ -3,6 +3,8 @@ package org.hswebframework.web.authorization.token;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 1.0
|
||||
@@ -20,6 +22,6 @@ public interface ThirdPartAuthenticationManager {
|
||||
* @param userId 用户ID
|
||||
* @return 权限信息
|
||||
*/
|
||||
Mono<Authentication> getByUserId(String userId);
|
||||
Optional<Authentication> getByUserId(String userId);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.hswebframework.web.authorization.token;
|
||||
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface ThirdPartReactiveAuthenticationManager {
|
||||
|
||||
/**
|
||||
* @return 支持的tokenType
|
||||
*/
|
||||
String getTokenType();
|
||||
|
||||
/**
|
||||
* 根据用户ID获取权限信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 权限信息
|
||||
*/
|
||||
Mono<Authentication> getByUserId(String userId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.hswebframework.web.authorization.token;
|
||||
|
||||
import org.hswebframework.web.authorization.*;
|
||||
import org.hswebframework.web.context.ContextKey;
|
||||
import org.hswebframework.web.context.ContextUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class UserTokenAuthenticationSupplier implements AuthenticationSupplier {
|
||||
|
||||
private AuthenticationManager defaultAuthenticationManager;
|
||||
|
||||
private UserTokenManager userTokenManager;
|
||||
|
||||
private Map<String, ThirdPartAuthenticationManager> thirdPartAuthenticationManager = new HashMap<>();
|
||||
|
||||
public UserTokenAuthenticationSupplier(UserTokenManager userTokenManager, AuthenticationManager defaultAuthenticationManager) {
|
||||
this.defaultAuthenticationManager = defaultAuthenticationManager;
|
||||
this.userTokenManager = userTokenManager;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setThirdPartAuthenticationManager(List<ThirdPartAuthenticationManager> thirdPartReactiveAuthenticationManager) {
|
||||
for (ThirdPartAuthenticationManager manager : thirdPartReactiveAuthenticationManager) {
|
||||
this.thirdPartAuthenticationManager.put(manager.getTokenType(), manager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Authentication> get(String userId) {
|
||||
if (userId == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return get(this.defaultAuthenticationManager, userId);
|
||||
}
|
||||
|
||||
protected Optional<Authentication> get(ThirdPartAuthenticationManager authenticationManager, String userId) {
|
||||
if (null == userId) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (null == authenticationManager) {
|
||||
return this.defaultAuthenticationManager.getByUserId(userId);
|
||||
}
|
||||
return authenticationManager.getByUserId(userId);
|
||||
}
|
||||
|
||||
protected Optional<Authentication> get(AuthenticationManager authenticationManager, String userId) {
|
||||
if (null == userId) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (null == authenticationManager) {
|
||||
authenticationManager = this.defaultAuthenticationManager;
|
||||
}
|
||||
return authenticationManager.getByUserId(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Authentication> get() {
|
||||
|
||||
return ContextUtils.currentContext()
|
||||
.get(ContextKey.of(ParsedToken.class))
|
||||
.map(t -> userTokenManager.getByToken(t.getToken()))
|
||||
.map(tokenMono -> tokenMono
|
||||
.map(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId()))
|
||||
.flatMap(Mono::justOrEmpty))
|
||||
.flatMap(Mono::blockOptional);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.hswebframework.web.authorization.token;
|
||||
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.AuthenticationManager;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationSupplier;
|
||||
import org.hswebframework.web.context.ContextKey;
|
||||
import org.hswebframework.web.context.ContextUtils;
|
||||
@@ -17,20 +17,20 @@ import java.util.Map;
|
||||
*/
|
||||
public class UserTokenReactiveAuthenticationSupplier implements ReactiveAuthenticationSupplier {
|
||||
|
||||
private AuthenticationManager defaultAuthenticationManager;
|
||||
private ReactiveAuthenticationManager defaultAuthenticationManager;
|
||||
|
||||
private UserTokenManager userTokenManager;
|
||||
|
||||
private Map<String, ThirdPartAuthenticationManager> thirdPartAuthenticationManager = new HashMap<>();
|
||||
private Map<String, ThirdPartReactiveAuthenticationManager> thirdPartAuthenticationManager = new HashMap<>();
|
||||
|
||||
public UserTokenReactiveAuthenticationSupplier(UserTokenManager userTokenManager, AuthenticationManager defaultAuthenticationManager) {
|
||||
public UserTokenReactiveAuthenticationSupplier(UserTokenManager userTokenManager, ReactiveAuthenticationManager defaultAuthenticationManager) {
|
||||
this.defaultAuthenticationManager = defaultAuthenticationManager;
|
||||
this.userTokenManager=userTokenManager;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setThirdPartAuthenticationManager(List<ThirdPartAuthenticationManager> thirdPartAuthenticationManager) {
|
||||
for (ThirdPartAuthenticationManager manager : thirdPartAuthenticationManager) {
|
||||
public void setThirdPartAuthenticationManager(List<ThirdPartReactiveAuthenticationManager> thirdPartReactiveAuthenticationManager) {
|
||||
for (ThirdPartReactiveAuthenticationManager manager : thirdPartReactiveAuthenticationManager) {
|
||||
this.thirdPartAuthenticationManager.put(manager.getTokenType(), manager);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class UserTokenReactiveAuthenticationSupplier implements ReactiveAuthenti
|
||||
return get(this.defaultAuthenticationManager, userId);
|
||||
}
|
||||
|
||||
protected Mono<Authentication> get(ThirdPartAuthenticationManager authenticationManager, String userId) {
|
||||
protected Mono<Authentication> get(ThirdPartReactiveAuthenticationManager authenticationManager, String userId) {
|
||||
if (null == userId) {
|
||||
return null;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public class UserTokenReactiveAuthenticationSupplier implements ReactiveAuthenti
|
||||
return authenticationManager.getByUserId(userId);
|
||||
}
|
||||
|
||||
protected Mono<Authentication> get(AuthenticationManager authenticationManager, String userId) {
|
||||
protected Mono<Authentication> get(ReactiveAuthenticationManager authenticationManager, String userId) {
|
||||
if (null == userId) {
|
||||
return null;
|
||||
}
|
||||
@@ -69,7 +69,8 @@ public class UserTokenReactiveAuthenticationSupplier implements ReactiveAuthenti
|
||||
.flatMap(context ->
|
||||
context.get(ContextKey.of(ParsedToken.class))
|
||||
.map(t -> userTokenManager.getByToken(t.getToken()))
|
||||
.map(tokenMono -> tokenMono.flatMap(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId())))
|
||||
.map(tokenMono -> tokenMono
|
||||
.flatMap(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId())))
|
||||
.orElseGet(Mono::empty));
|
||||
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public class AuthenticationTests {
|
||||
.build();
|
||||
|
||||
//初始化权限管理器,用于获取用户的权限信息
|
||||
AuthenticationManager authenticationManager = new AuthenticationManager() {
|
||||
ReactiveAuthenticationManager authenticationManager = new ReactiveAuthenticationManager() {
|
||||
@Override
|
||||
public Mono<Authentication> authenticate(Mono<AuthenticationRequest> request) {
|
||||
return Mono.empty();
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.hswebframework.web.authorization.basic.configuration;
|
||||
|
||||
import org.hswebframework.web.authorization.AuthenticationManager;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.authorization.access.DataAccessController;
|
||||
import org.hswebframework.web.authorization.access.DataAccessHandler;
|
||||
import org.hswebframework.web.authorization.basic.aop.AopMethodAuthorizeDefinitionParser;
|
||||
import org.hswebframework.web.authorization.basic.embed.EmbedAuthenticationManager;
|
||||
import org.hswebframework.web.authorization.basic.embed.EmbedAuthenticationProperties;
|
||||
import org.hswebframework.web.authorization.basic.embed.EmbedReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.authorization.basic.handler.DefaultAuthorizingHandler;
|
||||
import org.hswebframework.web.authorization.basic.handler.UserAllowPermissionHandler;
|
||||
import org.hswebframework.web.authorization.basic.handler.access.DefaultDataAccessController;
|
||||
@@ -16,6 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.condition.*;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -33,6 +36,7 @@ import java.util.List;
|
||||
* @since 3.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(EmbedAuthenticationProperties.class)
|
||||
public class AuthorizingHandlerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -85,19 +89,19 @@ public class AuthorizingHandlerAutoConfiguration {
|
||||
AopMethodAuthorizeDefinitionParser parser,
|
||||
List<UserTokenParser> userTokenParser) {
|
||||
|
||||
return new WebMvcConfigurerAdapter() {
|
||||
return new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new WebUserTokenInterceptor(userTokenManager, userTokenParser, parser));
|
||||
super.addInterceptors(registry);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AuthenticationManager.class)
|
||||
public AuthenticationManager embedAuthenticationManager() {
|
||||
return new EmbedAuthenticationManager();
|
||||
@ConditionalOnMissingBean(ReactiveAuthenticationManager.class)
|
||||
public ReactiveAuthenticationManager embedAuthenticationManager(EmbedAuthenticationProperties properties) {
|
||||
return new EmbedReactiveAuthenticationManager(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -130,8 +134,9 @@ public class AuthorizingHandlerAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserTokenController userTokenController() {
|
||||
return new UserTokenController();
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
public ReactiveUserTokenController userTokenController() {
|
||||
return new ReactiveUserTokenController();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -60,8 +60,8 @@ public class BasicAuthorizationTokenParser implements UserTokenForTypeParser {
|
||||
if (usernameAndPassword.contains(":")) {
|
||||
String[] arr = usernameAndPassword.split("[:]");
|
||||
Authentication authentication = authenticationManager
|
||||
.authenticate(Mono.just(new PlainTextUsernamePasswordAuthenticationRequest(arr[0], arr[1])))
|
||||
.blockOptional().orElse(null);
|
||||
.authenticate(new PlainTextUsernamePasswordAuthenticationRequest(arr[0], arr[1]))
|
||||
;
|
||||
if (authentication != null) {
|
||||
return new AuthorizedToken() {
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package org.hswebframework.web.authorization.basic.embed;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.Permission;
|
||||
import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory;
|
||||
import org.hswebframework.web.authorization.simple.SimpleAuthentication;
|
||||
import org.hswebframework.web.authorization.simple.SimplePermission;
|
||||
import org.hswebframework.web.authorization.simple.SimpleRole;
|
||||
import org.hswebframework.web.authorization.simple.SimpleUser;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* hsweb:
|
||||
* users:
|
||||
* admin:
|
||||
* name: 超级管理员
|
||||
* username: admin
|
||||
* password: admin
|
||||
* roles:
|
||||
* - id: admin
|
||||
* name: 管理员
|
||||
* - id: user
|
||||
* name: 用户
|
||||
* permissions:
|
||||
* - id: user-manager
|
||||
* actions: *
|
||||
* dataAccesses:
|
||||
* - action: query
|
||||
* type: DENY_FIELDS
|
||||
* fields: password,salt
|
||||
* </pre>
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0.0-RC
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class EmbedAuthenticationInfo {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String username;
|
||||
|
||||
private String type;
|
||||
|
||||
private String password;
|
||||
|
||||
private List<SimpleRole> roles = new ArrayList<>();
|
||||
|
||||
private List<PermissionInfo> permissions = new ArrayList<>();
|
||||
|
||||
private Map<String, List<String>> permissionsSimple = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class PermissionInfo {
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Set<String> actions = new HashSet<>();
|
||||
|
||||
private List<Map<String, Object>> dataAccesses = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Authentication toAuthentication(DataAccessConfigBuilderFactory factory) {
|
||||
SimpleAuthentication authentication = new SimpleAuthentication();
|
||||
SimpleUser user = new SimpleUser();
|
||||
user.setId(id);
|
||||
user.setName(name);
|
||||
user.setUsername(username);
|
||||
user.setType(type);
|
||||
authentication.setUser(user);
|
||||
authentication.setRoles((List) roles);
|
||||
List<Permission> permissionList = new ArrayList<>();
|
||||
|
||||
permissionList.addAll(permissions.stream()
|
||||
.map(info -> {
|
||||
SimplePermission permission = new SimplePermission();
|
||||
permission.setId(info.getId());
|
||||
permission.setName(info.getName());
|
||||
permission.setActions(info.getActions());
|
||||
permission.setDataAccesses(info.getDataAccesses()
|
||||
.stream().map(conf -> factory.create()
|
||||
.fromMap(conf)
|
||||
.build()).collect(Collectors.toSet()));
|
||||
return permission;
|
||||
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
permissionList.addAll(permissionsSimple.entrySet().stream()
|
||||
.map(entry -> {
|
||||
SimplePermission permission = new SimplePermission();
|
||||
permission.setId(entry.getKey());
|
||||
permission.setActions(new HashSet<>(entry.getValue()));
|
||||
return permission;
|
||||
}).collect(Collectors.toList()));
|
||||
|
||||
authentication.setPermissions(permissionList);
|
||||
return authentication;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +1,37 @@
|
||||
package org.hswebframework.web.authorization.basic.embed;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.AuthenticationManager;
|
||||
import org.hswebframework.web.authorization.AuthenticationRequest;
|
||||
import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory;
|
||||
import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest;
|
||||
import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.StringUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.validation.ValidationException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 3.0.0-RC
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "hsweb")
|
||||
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class EmbedAuthenticationManager implements AuthenticationManager {
|
||||
|
||||
private Map<String, Authentication> authentications = new HashMap<>();
|
||||
|
||||
@Autowired(required = false)
|
||||
private DataAccessConfigBuilderFactory dataAccessConfigBuilderFactory = new SimpleDataAccessConfigBuilderFactory();
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private Map<String, EmbedAuthenticationProperties> users = new HashMap<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
users.forEach((id, properties) -> {
|
||||
if (StringUtils.isEmpty(properties.getId())) {
|
||||
properties.setId(id);
|
||||
}
|
||||
for (EmbedAuthenticationProperties.PermissionInfo permissionInfo : properties.getPermissions()) {
|
||||
for (Map<String, Object> objectMap : permissionInfo.getDataAccesses()) {
|
||||
for (Map.Entry<String, Object> stringObjectEntry : objectMap.entrySet()) {
|
||||
if (stringObjectEntry.getValue() instanceof Map) {
|
||||
Map<?, ?> mapVal = ((Map) stringObjectEntry.getValue());
|
||||
boolean maybeIsList = mapVal.keySet().stream().allMatch(org.hswebframework.utils.StringUtils::isInt);
|
||||
if (maybeIsList) {
|
||||
stringObjectEntry.setValue(mapVal.values());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
authentications.put(id, properties.toAuthentication(dataAccessConfigBuilderFactory));
|
||||
});
|
||||
}
|
||||
@Autowired
|
||||
private EmbedAuthenticationProperties properties;
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> authenticate(Mono<AuthenticationRequest> request) {
|
||||
return request.filter(r -> r instanceof PlainTextUsernamePasswordAuthenticationRequest)
|
||||
.map(PlainTextUsernamePasswordAuthenticationRequest.class::cast)
|
||||
.map(pwdReq -> users.values()
|
||||
.stream()
|
||||
.filter(user ->
|
||||
pwdReq.getUsername().equals(user.getUsername())
|
||||
&& pwdReq.getPassword().equals(user.getPassword()))
|
||||
.findFirst()
|
||||
.map(EmbedAuthenticationProperties::getId)
|
||||
.map(authentications::get)
|
||||
.orElseThrow(() -> new ValidationException("用户不存在")));
|
||||
public Authentication authenticate(AuthenticationRequest request) {
|
||||
return properties.authenticate(request);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> getByUserId(String userId) {
|
||||
return Mono.just(authentications.get(userId));
|
||||
public Optional<Authentication> getByUserId(String userId) {
|
||||
return properties.getAuthentication(userId);
|
||||
}
|
||||
|
||||
void addAuthentication(Authentication authentication) {
|
||||
authentications.put(authentication.getUser().getId(), authentication);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
package org.hswebframework.web.authorization.basic.embed;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.Permission;
|
||||
import org.hswebframework.web.authorization.Role;
|
||||
import org.hswebframework.web.authorization.AuthenticationRequest;
|
||||
import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory;
|
||||
import org.hswebframework.web.authorization.simple.SimpleAuthentication;
|
||||
import org.hswebframework.web.authorization.simple.SimplePermission;
|
||||
import org.hswebframework.web.authorization.simple.SimpleRole;
|
||||
import org.hswebframework.web.authorization.simple.SimpleUser;
|
||||
import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest;
|
||||
import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.validation.ValidationException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* hsweb:
|
||||
* auth:
|
||||
* users:
|
||||
* admin:
|
||||
* name: 超级管理员
|
||||
@@ -42,72 +46,61 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class EmbedAuthenticationProperties {
|
||||
@ConfigurationProperties(prefix = "hsweb.auth")
|
||||
public class EmbedAuthenticationProperties implements InitializingBean {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String username;
|
||||
|
||||
private String type;
|
||||
|
||||
private String password;
|
||||
|
||||
private List<SimpleRole> roles = new ArrayList<>();
|
||||
|
||||
private List<PermissionInfo> permissions = new ArrayList<>();
|
||||
|
||||
private Map<String, List<String>> permissionsSimple = new HashMap<>();
|
||||
private Map<String, Authentication> authentications = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class PermissionInfo {
|
||||
private String id;
|
||||
private Map<String, EmbedAuthenticationInfo> users = new HashMap<>();
|
||||
|
||||
private String name;
|
||||
@Autowired(required = false)
|
||||
private DataAccessConfigBuilderFactory dataAccessConfigBuilderFactory = new SimpleDataAccessConfigBuilderFactory();
|
||||
|
||||
private Set<String> actions = new HashSet<>();
|
||||
|
||||
private List<Map<String, Object>> dataAccesses = new ArrayList<>();
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
users.forEach((id, properties) -> {
|
||||
if (StringUtils.isEmpty(properties.getId())) {
|
||||
properties.setId(id);
|
||||
}
|
||||
for (EmbedAuthenticationInfo.PermissionInfo permissionInfo : properties.getPermissions()) {
|
||||
for (Map<String, Object> objectMap : permissionInfo.getDataAccesses()) {
|
||||
for (Map.Entry<String, Object> stringObjectEntry : objectMap.entrySet()) {
|
||||
if (stringObjectEntry.getValue() instanceof Map) {
|
||||
Map<?, ?> mapVal = ((Map) stringObjectEntry.getValue());
|
||||
boolean maybeIsList = mapVal.keySet().stream().allMatch(org.hswebframework.utils.StringUtils::isInt);
|
||||
if (maybeIsList) {
|
||||
stringObjectEntry.setValue(mapVal.values());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
authentications.put(id, properties.toAuthentication(dataAccessConfigBuilderFactory));
|
||||
});
|
||||
}
|
||||
|
||||
public Authentication toAuthentication(DataAccessConfigBuilderFactory factory) {
|
||||
SimpleAuthentication authentication = new SimpleAuthentication();
|
||||
SimpleUser user = new SimpleUser();
|
||||
user.setId(id);
|
||||
user.setName(name);
|
||||
user.setUsername(username);
|
||||
user.setType(type);
|
||||
authentication.setUser(user);
|
||||
authentication.setRoles((List) roles);
|
||||
List<Permission> permissionList = new ArrayList<>();
|
||||
public Authentication authenticate(AuthenticationRequest request) {
|
||||
if(request instanceof PlainTextUsernamePasswordAuthenticationRequest){
|
||||
PlainTextUsernamePasswordAuthenticationRequest pwdReq = ((PlainTextUsernamePasswordAuthenticationRequest) request);
|
||||
return users.values()
|
||||
.stream()
|
||||
.filter(user ->
|
||||
pwdReq.getUsername().equals(user.getUsername())
|
||||
&& pwdReq.getPassword().equals(user.getPassword()))
|
||||
.findFirst()
|
||||
.map(EmbedAuthenticationInfo::getId)
|
||||
.map(authentications::get)
|
||||
.orElseThrow(() -> new ValidationException("用户不存在"));
|
||||
}
|
||||
|
||||
permissionList.addAll(permissions.stream()
|
||||
.map(info -> {
|
||||
SimplePermission permission = new SimplePermission();
|
||||
permission.setId(info.getId());
|
||||
permission.setName(info.getName());
|
||||
permission.setActions(info.getActions());
|
||||
permission.setDataAccesses(info.getDataAccesses()
|
||||
.stream().map(conf -> factory.create()
|
||||
.fromJson(JSON.toJSONString(conf))
|
||||
.build()).collect(Collectors.toSet()));
|
||||
return permission;
|
||||
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
permissionList.addAll(permissionsSimple.entrySet().stream()
|
||||
.map(entry -> {
|
||||
SimplePermission permission = new SimplePermission();
|
||||
permission.setId(entry.getKey());
|
||||
permission.setActions(new HashSet<>(entry.getValue()));
|
||||
return permission;
|
||||
}).collect(Collectors.toList()));
|
||||
|
||||
authentication.setPermissions(permissionList);
|
||||
return authentication;
|
||||
throw new UnsupportedOperationException("不支持的授权请求:"+request);
|
||||
}
|
||||
|
||||
public Optional<Authentication> getAuthentication(String userId) {
|
||||
return Optional.ofNullable(authentications.get(userId));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.hswebframework.web.authorization.basic.embed;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.AuthenticationRequest;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 3.0.0-RC
|
||||
*/
|
||||
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@AllArgsConstructor
|
||||
public class EmbedReactiveAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
|
||||
private EmbedAuthenticationProperties properties;
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> authenticate(Mono<AuthenticationRequest> request) {
|
||||
return request.map(properties::authenticate);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> getByUserId(String userId) {
|
||||
return Mono.justOrEmpty(properties.getAuthentication(userId));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -31,7 +31,6 @@ public final class DefaultDataAccessController implements DataAccessController {
|
||||
}
|
||||
this.parent = parent;
|
||||
addHandler(new CustomDataAccessHandler()).
|
||||
addHandler(new ScriptDataAccessHandler()).
|
||||
addHandler(new FieldFilterDataAccessHandler()).
|
||||
addHandler(new FieldScopeDataAccessHandler());
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package org.hswebframework.web.authorization.basic.handler.access;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.hswebframework.expands.script.engine.DynamicScriptEngine;
|
||||
import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory;
|
||||
import org.hswebframework.utils.StringUtils;
|
||||
import org.hswebframework.web.exception.BusinessException;
|
||||
import org.hswebframework.web.authorization.access.DataAccessConfig;
|
||||
import org.hswebframework.web.authorization.access.DataAccessHandler;
|
||||
import org.hswebframework.web.authorization.access.ScriptDataAccessConfig;
|
||||
import org.hswebframework.web.authorization.define.AuthorizingContext;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class ScriptDataAccessHandler implements DataAccessHandler {
|
||||
@Override
|
||||
public boolean isSupport(DataAccessConfig access) {
|
||||
return access instanceof ScriptDataAccessConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(DataAccessConfig access, AuthorizingContext context) {
|
||||
ScriptDataAccessConfig dataAccess = ((ScriptDataAccessConfig) access);
|
||||
DynamicScriptEngine engine = DynamicScriptEngineFactory.getEngine(dataAccess.getScriptLanguage());
|
||||
if (engine == null) {
|
||||
throw new UnsupportedOperationException(dataAccess.getScriptLanguage() + " {not_support}");
|
||||
}
|
||||
String scriptId = DigestUtils.md5Hex(dataAccess.getScript());
|
||||
try {
|
||||
if (!engine.compiled(scriptId)) {
|
||||
engine.compile(scriptId, dataAccess.getScript());
|
||||
}
|
||||
Object success = engine.execute(scriptId, context.getParamContext().getParams()).getIfSuccess();
|
||||
return StringUtils.isTrue(success);
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("{script_error}", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import io.swagger.annotations.ApiParam;
|
||||
import lombok.SneakyThrows;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.AuthenticationManager;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.hswebframework.web.authorization.events.*;
|
||||
import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest;
|
||||
@@ -48,7 +49,7 @@ import java.util.function.Function;
|
||||
public class AuthorizationController {
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
private ReactiveAuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiOperation;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.AuthenticationManager;
|
||||
import org.hswebframework.web.authorization.Permission;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.hswebframework.web.authorization.exception.UnAuthorizedException;
|
||||
import org.hswebframework.web.authorization.token.TokenState;
|
||||
@@ -22,10 +23,10 @@ import reactor.core.publisher.Mono;
|
||||
@RequestMapping
|
||||
@Authorize(permission = "user-token", description = "用户令牌信息管理")
|
||||
@Api(tags = "权限-用户令牌管理", value = "权限-用户令牌管理")
|
||||
public class UserTokenController {
|
||||
public class ReactiveUserTokenController {
|
||||
private UserTokenManager userTokenManager;
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
private ReactiveAuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired
|
||||
@Lazy
|
||||
@@ -35,7 +36,7 @@ public class UserTokenController {
|
||||
|
||||
@Autowired
|
||||
@Lazy
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
public void setAuthenticationManager(ReactiveAuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
@@ -1,43 +1,15 @@
|
||||
package org.hswebframework.web.authorization.basic.aop;
|
||||
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.basic.configuration.EnableAopAuthorize;
|
||||
import org.hswebframework.web.authorization.basic.web.GeneratedToken;
|
||||
import org.hswebframework.web.authorization.basic.web.ReactiveUserTokenGenerator;
|
||||
import org.hswebframework.web.authorization.basic.web.ReactiveUserTokenParser;
|
||||
import org.hswebframework.web.authorization.token.ParsedToken;
|
||||
import org.hswebframework.web.id.IDGenerator;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext;
|
||||
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
@SpringBootApplication(exclude = {
|
||||
WebMvcAutoConfiguration.class,
|
||||
ServletWebServerFactoryAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class})
|
||||
@SpringBootApplication
|
||||
@EnableAopAuthorize
|
||||
public class TestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication application=new SpringApplication(TestApplication.class);
|
||||
application.setApplicationContextClass(ReactiveWebServerApplicationContext.class);
|
||||
application.run(args);
|
||||
SpringApplication.run(TestApplication.class,args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package org.hswebframework.web.authorization.basic.aop;
|
||||
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.AuthenticationManager;
|
||||
import org.hswebframework.web.authorization.User;
|
||||
import org.hswebframework.web.authorization.basic.web.GeneratedToken;
|
||||
import org.hswebframework.web.authorization.basic.web.ReactiveUserTokenGenerator;
|
||||
import org.hswebframework.web.authorization.basic.web.ReactiveUserTokenParser;
|
||||
import org.hswebframework.web.authorization.simple.DefaultAuthorizationAutoConfiguration;
|
||||
import org.hswebframework.web.authorization.token.ParsedToken;
|
||||
import org.hswebframework.web.authorization.token.UserTokenManager;
|
||||
import org.hswebframework.web.id.IDGenerator;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
@WebFluxTest(FluxTestController.class)
|
||||
@RunWith(SpringRunner.class)
|
||||
@Import(DefaultAuthorizationAutoConfiguration.class)
|
||||
public class WebFluxTests {
|
||||
|
||||
@Autowired
|
||||
private WebTestClient client;
|
||||
|
||||
@Autowired
|
||||
private UserTokenManager tokenManager;
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
|
||||
tokenManager.signIn("test","test-token","admin",10000).block();
|
||||
|
||||
client.get().uri("/test")
|
||||
.header("token","test")
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
hsweb:
|
||||
users:
|
||||
auth:
|
||||
users:
|
||||
admin:
|
||||
username: admin
|
||||
password: admin
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -9,6 +9,8 @@ import org.hswebframework.web.crud.annotation.EnableEasyormRepository;
|
||||
import org.hswebframework.web.api.crud.entity.ImplementFor;
|
||||
import org.hswebframework.web.crud.annotation.Reactive;
|
||||
import org.hswebframework.web.api.crud.entity.GenericEntity;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -138,13 +140,21 @@ public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar
|
||||
registry.registerBeanDefinition(realType.getSimpleName().concat("SyncRepository"), definition);
|
||||
}
|
||||
|
||||
RootBeanDefinition definition = new RootBeanDefinition();
|
||||
definition.setTargetType(AutoDDLProcessor.class);
|
||||
definition.setBeanClass(AutoDDLProcessor.class);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
definition.getPropertyValues().add("entities", entityInfos);
|
||||
definition.getPropertyValues().add("reactive", reactive);
|
||||
registry.registerBeanDefinition(AutoDDLProcessor.class.getName(), definition);
|
||||
|
||||
try {
|
||||
BeanDefinition definition = registry.getBeanDefinition(AutoDDLProcessor.class.getName());
|
||||
Set<EntityInfo> infos = (Set) definition.getPropertyValues().get("entities");
|
||||
infos.addAll(entityInfos);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
RootBeanDefinition definition = new RootBeanDefinition();
|
||||
definition.setTargetType(AutoDDLProcessor.class);
|
||||
definition.setBeanClass(AutoDDLProcessor.class);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
definition.getPropertyValues().add("entities", entityInfos);
|
||||
definition.getPropertyValues().add("reactive", reactive);
|
||||
registry.registerBeanDefinition(AutoDDLProcessor.class.getName(), definition);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.hswebframework.web.event;
|
||||
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* 动态泛型事件,用于动态发布支持泛型的事件
|
||||
* <pre>
|
||||
* //相当于发布事件: EntityModifyEvent<UserEntity>
|
||||
* eventPublisher
|
||||
* .publishEvent(new GenericsPayloadApplicationEvent<>(this, new EntityModifyEvent<>(oldEntity, newEntity), UserEntity.class));
|
||||
*
|
||||
* //只监听相同泛型事件
|
||||
* @EventListener
|
||||
* public handleEvent(EntityModifyEvent<UserEntity> event){
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0.7
|
||||
*/
|
||||
public class GenericsPayloadApplicationEvent<E> extends PayloadApplicationEvent<E> {
|
||||
|
||||
private static final long serialVersionUID = 3745888943307798710L;
|
||||
|
||||
//泛型列表
|
||||
private transient Class[] generics;
|
||||
|
||||
//事件类型
|
||||
private transient Class eventType;
|
||||
|
||||
/**
|
||||
* @param source 事件源
|
||||
* @param payload 事件,不能使用匿名内部类
|
||||
* @param generics 泛型列表
|
||||
*/
|
||||
public GenericsPayloadApplicationEvent(Object source, E payload, Class... generics) {
|
||||
super(source, payload);
|
||||
this.generics = generics;
|
||||
this.eventType = payload.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvableType getResolvableType() {
|
||||
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class
|
||||
, ResolvableType.forClassWithGenerics(eventType, generics));
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
package org.hswebframework.web.system.authorization.api.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.*;
|
||||
import org.hswebframework.web.api.crud.entity.Entity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ActionEntity implements Entity {
|
||||
|
||||
private String action;
|
||||
|
||||
@@ -7,10 +7,7 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
|
||||
import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec;
|
||||
import org.hswebframework.web.api.crud.entity.Entity;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.*;
|
||||
import java.sql.JDBCType;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -23,6 +20,7 @@ import java.util.Set;
|
||||
public class AuthorizationSettingEntity implements Entity {
|
||||
@Id
|
||||
@Column(length = 32)
|
||||
@GeneratedValue(generator = "md5")
|
||||
private String id;
|
||||
|
||||
@Column(length = 32, nullable = false, updatable = false)
|
||||
@@ -55,10 +53,15 @@ public class AuthorizationSettingEntity implements Entity {
|
||||
@Comment("可操作权限")
|
||||
private Set<String> actions;
|
||||
|
||||
@Column
|
||||
@Column(name = "data_accesses")
|
||||
@ColumnType(jdbcType = JDBCType.CLOB)
|
||||
@JsonCodec
|
||||
@Comment("数据权限")
|
||||
private List<DataAccessEntity> dataAccesses;
|
||||
|
||||
@Column
|
||||
private Integer priority;
|
||||
|
||||
@Column
|
||||
private Boolean merge;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.Set;
|
||||
@Setter
|
||||
public class DataAccessEntity {
|
||||
|
||||
private Set<String> actions;
|
||||
private String action;
|
||||
|
||||
private String type;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.hswebframework.web.system.authorization.api.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.*;
|
||||
import org.hswebframework.ezorm.rdb.mapping.annotation.ColumnType;
|
||||
import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
|
||||
import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec;
|
||||
@@ -9,6 +8,7 @@ import org.hswebframework.web.api.crud.entity.GenericEntity;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.sql.JDBCType;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -16,6 +16,9 @@ import java.util.Map;
|
||||
@Table(name = "s_permission")
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PermissionEntity extends GenericEntity<String> {
|
||||
|
||||
@Column
|
||||
@@ -26,7 +29,7 @@ public class PermissionEntity extends GenericEntity<String> {
|
||||
@Comment("说明")
|
||||
private String describe;
|
||||
|
||||
@Column
|
||||
@Column(nullable = false)
|
||||
@Comment("状态")
|
||||
private Byte status;
|
||||
|
||||
|
||||
@@ -67,6 +67,24 @@
|
||||
<artifactId>r2dbc-h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-authorization-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.configuration;
|
||||
|
||||
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.system.authorization.api.UserPermissionDimensionProvider;
|
||||
import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService;
|
||||
import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveAuthenticationInitializeService;
|
||||
import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveUserService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
@Configuration
|
||||
public class AuthorizationServiceAutoConfiguration {
|
||||
|
||||
|
||||
// TODO: 2019-10-12 condition reactive enabled
|
||||
@Configuration
|
||||
static class ReactiveAuthorizationServiceAutoConfiguration{
|
||||
@ConditionalOnBean(ReactiveRepository.class)
|
||||
@Bean
|
||||
public ReactiveUserService reactiveUserService() {
|
||||
return new DefaultReactiveUserService();
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnBean(ReactiveUserService.class)
|
||||
@Bean
|
||||
public ReactiveAuthenticationManager reactiveAuthenticationManager() {
|
||||
return new DefaultReactiveAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(ReactiveUserService.class)
|
||||
public ReactiveAuthenticationInitializeService reactiveAuthenticationInitializeService() {
|
||||
return new DefaultReactiveAuthenticationInitializeService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserPermissionDimensionProvider userPermissionDimensionProvider(){
|
||||
return new UserPermissionDimensionProvider();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.configuration;
|
||||
|
||||
import org.hswebframework.web.system.authorization.defaults.webflux.WebFluxPermissionController;
|
||||
import org.hswebframework.web.system.authorization.defaults.webflux.WebFluxUserController;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class AuthorizationWebAutoConfiguration {
|
||||
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
public static class WebFluxAuthorizationConfiguration {
|
||||
|
||||
@Bean
|
||||
public WebFluxPermissionController webFluxPermissionController() {
|
||||
return new WebFluxPermissionController();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebFluxUserController webFluxUserController() {
|
||||
return new WebFluxUserController();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.service;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.Permission;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService;
|
||||
import org.hswebframework.web.authorization.access.DataAccessConfig;
|
||||
import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory;
|
||||
import org.hswebframework.web.authorization.simple.SimpleAuthentication;
|
||||
import org.hswebframework.web.authorization.simple.SimplePermission;
|
||||
import org.hswebframework.web.authorization.simple.SimpleUser;
|
||||
import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory;
|
||||
import org.hswebframework.web.system.authorization.api.PermissionDimension;
|
||||
import org.hswebframework.web.system.authorization.api.PermissionDimensionProvider;
|
||||
import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity;
|
||||
import org.hswebframework.web.system.authorization.api.entity.PermissionEntity;
|
||||
import org.hswebframework.web.system.authorization.api.entity.UserEntity;
|
||||
import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DefaultReactiveAuthenticationInitializeService
|
||||
implements ReactiveAuthenticationInitializeService {
|
||||
|
||||
@Autowired
|
||||
private ReactiveUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepository<AuthorizationSettingEntity, String> settingRepository;
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepository<PermissionEntity, String> permissionRepository;
|
||||
|
||||
@Autowired(required = false)
|
||||
private DataAccessConfigBuilderFactory builderFactory = new SimpleDataAccessConfigBuilderFactory();
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<PermissionDimensionProvider> dimensionProviders = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> initUserAuthorization(String userId) {
|
||||
return doInit(userService.findById(userId));
|
||||
}
|
||||
|
||||
public Mono<Authentication> doInit(Mono<UserEntity> userEntityMono) {
|
||||
|
||||
return userEntityMono.flatMap(user -> {
|
||||
SimpleAuthentication authentication = new SimpleAuthentication();
|
||||
authentication.setUser(SimpleUser
|
||||
.builder()
|
||||
.id(user.getId())
|
||||
.name(user.getName())
|
||||
.username(user.getUsername())
|
||||
.type(user.getType())
|
||||
.build());
|
||||
return initPermission(authentication);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected Mono<Authentication> initPermission(SimpleAuthentication authentication) {
|
||||
return Flux.fromIterable(dimensionProviders)
|
||||
.flatMap(provider -> provider.getDimensionByUserId(authentication.getUser().getId()))
|
||||
.collectList()
|
||||
.flatMap(allDimension -> Mono.zip(getAllPermission(),
|
||||
settingRepository
|
||||
.createQuery()
|
||||
.where(AuthorizationSettingEntity::getState, 1)
|
||||
.in(AuthorizationSettingEntity::getDimension, allDimension
|
||||
.stream()
|
||||
.map(PermissionDimension::getId)
|
||||
.collect(Collectors.toList()))
|
||||
.fetch()
|
||||
.collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission))
|
||||
, (_p, _s) -> handlePermission(authentication, allDimension, _p, _s)));
|
||||
|
||||
}
|
||||
|
||||
protected SimpleAuthentication handlePermission(SimpleAuthentication authentication,
|
||||
List<PermissionDimension> dimensionList,
|
||||
Map<String, PermissionEntity> permissions,
|
||||
Map<String, List<AuthorizationSettingEntity>> settings) {
|
||||
List<Permission> permissionList = new ArrayList<>();
|
||||
for (PermissionEntity value : permissions.values()) {
|
||||
List<AuthorizationSettingEntity> permissionSettings = settings.get(value.getId());
|
||||
if (CollectionUtils.isEmpty(permissionSettings)) {
|
||||
continue;
|
||||
}
|
||||
permissionSettings.sort(Comparator.comparingInt(e -> e.getPriority() == null ? 0 : e.getPriority()));
|
||||
SimplePermission permission = new SimplePermission();
|
||||
permission.setId(value.getId());
|
||||
permission.setName(value.getName());
|
||||
Map<String, DataAccessConfig> configs = new HashMap<>();
|
||||
|
||||
for (AuthorizationSettingEntity permissionSetting : permissionSettings) {
|
||||
|
||||
boolean merge = Boolean.TRUE.equals(permissionSetting.getMerge());
|
||||
|
||||
if (!merge) {
|
||||
permission.getActions().clear();
|
||||
}
|
||||
|
||||
if (permissionSetting.getDataAccesses() != null) {
|
||||
permissionSetting.getDataAccesses()
|
||||
.stream()
|
||||
.map(conf -> builderFactory.create().fromMap(conf.getConfig()).build())
|
||||
.forEach(access -> configs.put(access.getType(), access));
|
||||
}
|
||||
|
||||
permission.getActions().addAll(permissionSetting.getActions());
|
||||
|
||||
}
|
||||
permission.setDataAccesses(new HashSet<>(configs.values()));
|
||||
permissionList.add(permission);
|
||||
|
||||
}
|
||||
authentication.setPermissions(permissionList);
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
protected Mono<Map<String, PermissionEntity>> getAllPermission() {
|
||||
|
||||
return permissionRepository
|
||||
.createQuery()
|
||||
.where(PermissionEntity::getStatus, 1)
|
||||
.fetch()
|
||||
.collect(Collectors.toMap(PermissionEntity::getId, Function.identity()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.service;
|
||||
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.AuthenticationRequest;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.authorization.exception.AccessDenyException;
|
||||
import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest;
|
||||
import org.hswebframework.web.system.authorization.api.entity.UserEntity;
|
||||
import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.support.SimpleValueWrapper;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class DefaultReactiveAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
|
||||
@Autowired
|
||||
private ReactiveUserService reactiveUserService;
|
||||
|
||||
@Autowired
|
||||
private ReactiveAuthenticationInitializeService initializeService;
|
||||
|
||||
@Autowired(required = false)
|
||||
private CacheManager cacheManager;
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> authenticate(Mono<AuthenticationRequest> request) {
|
||||
return request
|
||||
.filter(PlainTextUsernamePasswordAuthenticationRequest.class::isInstance)
|
||||
.switchIfEmpty(Mono.error(() -> new UnsupportedOperationException("不支持的请求类型")))
|
||||
.map(PlainTextUsernamePasswordAuthenticationRequest.class::cast)
|
||||
.flatMap(pwdRequest -> reactiveUserService.findByUsernameAndPassword(pwdRequest.getUsername(), pwdRequest.getPassword()))
|
||||
.switchIfEmpty(Mono.error(() -> new AccessDenyException("密码错误")))
|
||||
.map(UserEntity::getId)
|
||||
.flatMap(this::getByUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> getByUserId(String userId) {
|
||||
|
||||
return Mono.justOrEmpty(userId)
|
||||
.flatMap(_id -> Mono.justOrEmpty(cacheManager)
|
||||
.map(cm -> cm.getCache("user-auth"))
|
||||
.flatMap(cache -> Mono.justOrEmpty(cache.get(userId))
|
||||
.switchIfEmpty(initializeService.initUserAuthorization(_id)
|
||||
.doOnNext(autz -> cache.put(userId, autz))
|
||||
.map(SimpleValueWrapper::new)))
|
||||
.flatMap(valueWrapper -> Mono.justOrEmpty(valueWrapper.get())))
|
||||
.cast(Authentication.class)
|
||||
.switchIfEmpty(initializeService.initUserAuthorization(userId))
|
||||
.cache();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.webflux;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
|
||||
import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
|
||||
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
|
||||
import org.hswebframework.web.authorization.Permission;
|
||||
import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.hswebframework.web.exception.NotFoundException;
|
||||
import org.hswebframework.web.system.authorization.api.entity.PermissionEntity;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/permission")
|
||||
@Authorize(permission = "permission", description = "权限管理")
|
||||
public class WebFluxPermissionController {
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepository<PermissionEntity, String> repository;
|
||||
|
||||
@GetMapping
|
||||
@Authorize(action = Permission.ACTION_QUERY)
|
||||
public Flux<PermissionEntity> findAllPermission(QueryParamEntity paramEntity) {
|
||||
return repository.createQuery()
|
||||
.setParam(paramEntity)
|
||||
.fetch();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Authorize(action = Permission.ACTION_QUERY)
|
||||
public Mono<PermissionEntity> getPermission(@PathVariable String id) {
|
||||
return Mono.just(id)
|
||||
.as(repository::findById)
|
||||
.switchIfEmpty(Mono.error(NotFoundException::new));
|
||||
}
|
||||
|
||||
@GetMapping("/count")
|
||||
@Authorize(action = Permission.ACTION_QUERY)
|
||||
public Mono<Integer> countAllPermission(QueryParamEntity paramEntity) {
|
||||
return repository.createQuery()
|
||||
.setParam(paramEntity)
|
||||
.count()
|
||||
.defaultIfEmpty(0);
|
||||
}
|
||||
|
||||
@PatchMapping
|
||||
@Authorize(action = Permission.ACTION_UPDATE)
|
||||
public Mono<SaveResult> savePermission(@RequestBody Publisher<PermissionEntity> paramEntity) {
|
||||
return repository.save(paramEntity);
|
||||
}
|
||||
|
||||
@PutMapping("/status/{status}")
|
||||
@Authorize(action = Permission.ACTION_UPDATE)
|
||||
public Mono<Integer> changePermissionState(@PathVariable Byte status, @RequestBody List<String> idList) {
|
||||
|
||||
return Mono.just(idList)
|
||||
.filter(CollectionUtils::isNotEmpty)
|
||||
.flatMap(list -> repository.createUpdate()
|
||||
.set(PermissionEntity::getStatus, status)
|
||||
.where()
|
||||
.in(PermissionEntity::getId, list)
|
||||
.execute())
|
||||
.defaultIfEmpty(0);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.webflux;
|
||||
|
||||
import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
@Authorize(permission = "user",description = "用户管理")
|
||||
public class WebFluxUserController {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Auto Configure
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.hswebframework.web.system.authorization.defaults.configuration.AuthorizationServiceAutoConfiguration,\
|
||||
org.hswebframework.web.system.authorization.defaults.configuration.AuthorizationWebAutoConfiguration
|
||||
@@ -0,0 +1,96 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.service.reactive;
|
||||
|
||||
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.authorization.User;
|
||||
import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest;
|
||||
import org.hswebframework.web.system.authorization.api.entity.ActionEntity;
|
||||
import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity;
|
||||
import org.hswebframework.web.system.authorization.api.entity.PermissionEntity;
|
||||
import org.hswebframework.web.system.authorization.api.entity.UserEntity;
|
||||
import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = ReactiveTestApplication.class)
|
||||
public class DefaultReactiveAuthenticationManagerTest {
|
||||
|
||||
@Autowired
|
||||
private ReactiveUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ReactiveAuthenticationManager reactiveAuthenticationManager;
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepository<PermissionEntity, String> permissionRepository;
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepository<AuthorizationSettingEntity, String> settingRepository;
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
UserEntity entity = new UserEntity();
|
||||
entity.setName("admin");
|
||||
entity.setUsername("admin");
|
||||
entity.setPassword("admin");
|
||||
|
||||
userService.saveUser(Mono.just(entity))
|
||||
.as(StepVerifier::create)
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
permissionRepository.newInstance()
|
||||
.map(permission -> {
|
||||
permission.setId("test");
|
||||
permission.setName("测试");
|
||||
permission.setActions(Arrays.asList(ActionEntity.builder().action("add").describe("新增").build()));
|
||||
permission.setStatus((byte) 1);
|
||||
return permission;
|
||||
})
|
||||
.as(permissionRepository::insert)
|
||||
.as(StepVerifier::create)
|
||||
.expectNext(1)
|
||||
.verifyComplete();
|
||||
|
||||
settingRepository.newInstance()
|
||||
.map(setting -> {
|
||||
setting.setPermission("test");
|
||||
setting.setActions(Collections.singleton("add"));
|
||||
setting.setDimension(entity.getId());
|
||||
setting.setDimensionName("测试用户");
|
||||
setting.setState((byte) 1);
|
||||
return setting;
|
||||
})
|
||||
.as(settingRepository::insert)
|
||||
.as(StepVerifier::create)
|
||||
.expectNext(1)
|
||||
.verifyComplete();
|
||||
|
||||
Mono<Authentication> authenticationMono = reactiveAuthenticationManager
|
||||
.authenticate(Mono.just(new PlainTextUsernamePasswordAuthenticationRequest("admin", "admin")))
|
||||
.cache();
|
||||
|
||||
authenticationMono.map(Authentication::getUser)
|
||||
.map(User::getName)
|
||||
.as(StepVerifier::create)
|
||||
.expectNext("admin")
|
||||
.verifyComplete();
|
||||
|
||||
authenticationMono.map(autz->autz.hasPermission("test","add"))
|
||||
.as(StepVerifier::create)
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.service.reactive;
|
||||
|
||||
import org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration;
|
||||
import org.hswebframework.web.system.authorization.api.UserPermissionDimensionProvider;
|
||||
import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveAuthenticationInitializeService;
|
||||
import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveAuthenticationManager;
|
||||
import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveUserService;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@@ -18,10 +21,4 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
public class ReactiveTestApplication {
|
||||
|
||||
|
||||
@Bean
|
||||
public DefaultReactiveUserService defaultReactiveUserService(){
|
||||
|
||||
return new DefaultReactiveUserService();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.hswebframework.web.system.authorization.defaults.service.reactive;
|
||||
|
||||
import org.hswebframework.web.crud.annotation.EnableEasyormRepository;
|
||||
import org.hswebframework.web.crud.configuration.EasyOrmConfiguration;
|
||||
import org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration;
|
||||
import org.hswebframework.web.crud.configuration.R2dbcSqlExecutorConfiguration;
|
||||
import org.hswebframework.web.system.authorization.api.entity.PermissionEntity;
|
||||
import org.hswebframework.web.system.authorization.defaults.configuration.AuthorizationWebAutoConfiguration;
|
||||
import org.hswebframework.web.system.authorization.defaults.webflux.WebFluxPermissionController;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.transaction.reactive.ReactiveTransactionAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebFluxTest(WebFluxPermissionController.class)
|
||||
@ImportAutoConfiguration(value = {
|
||||
AuthorizationWebAutoConfiguration.class, EasyOrmConfiguration.class,
|
||||
R2dbcSqlExecutorConfiguration.class, ConnectionFactoryAutoConfiguration.class,
|
||||
R2dbcTransactionManagerAutoConfiguration.class,
|
||||
ReactiveTransactionAutoConfiguration.class
|
||||
},exclude = {
|
||||
JdbcSqlExecutorConfiguration.class,
|
||||
TransactionAutoConfiguration.class
|
||||
})
|
||||
@EnableTransactionManagement
|
||||
public class WebFluxPermissionControllerTest {
|
||||
|
||||
@Autowired
|
||||
WebTestClient client;
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
byte[] data=client.get()
|
||||
.uri("/permission/count")
|
||||
//.contentType(MediaType.APPLICATION_JSON)
|
||||
// .body(Mono.just(PermissionEntity
|
||||
// .builder()
|
||||
// .name("test")
|
||||
// .build()),PermissionEntity.class)
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.returnResult()
|
||||
.getResponseBody();
|
||||
System.out.println(new String(data));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hsweb-system-authorization</artifactId>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hsweb-system-authorization-starter</artifactId>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hsweb-system-authorization</artifactId>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hsweb-system-authorization-web</artifactId>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -13,8 +13,6 @@
|
||||
<description>业务模块-权限管理</description>
|
||||
<modules>
|
||||
<module>hsweb-system-authorization-api</module>
|
||||
<module>hsweb-system-authorization-starter</module>
|
||||
<module>hsweb-system-authorization-web</module>
|
||||
<module>hsweb-system-authorization-default</module>
|
||||
</modules>
|
||||
<artifactId>hsweb-system-authorization</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user