This commit is contained in:
zhou-hao
2019-09-24 15:29:17 +08:00
parent 1c763faf67
commit 29945567cf
298 changed files with 986 additions and 8380 deletions

View File

@@ -17,6 +17,8 @@
package org.hswebframework.web.authorization;
import reactor.core.publisher.Mono;
import java.io.Serializable;
import java.util.*;
@@ -50,8 +52,8 @@ public interface Authentication extends Serializable {
* @see Optional
* @see AuthenticationHolder
*/
static Optional<Authentication> current() {
return Optional.ofNullable(AuthenticationHolder.get());
static Mono<Authentication> current() {
return AuthenticationHolder.get();
}
/**

View File

@@ -19,6 +19,8 @@
package org.hswebframework.web.authorization;
import org.hswebframework.web.ThreadLocalUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
@@ -26,6 +28,7 @@ import java.util.Objects;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 权限获取器,用于静态方式获取当前登录用户的权限信息.
@@ -45,31 +48,23 @@ import java.util.function.Function;
public final class AuthenticationHolder {
private static final List<AuthenticationSupplier> suppliers = new ArrayList<>();
private static final String CURRENT_USER_ID_KEY = Authentication.class.getName() + "_current_id";
private static final ReadWriteLock lock = new ReentrantReadWriteLock();
private static Authentication get(Function<AuthenticationSupplier, Authentication> function) {
lock.readLock().lock();
try {
return suppliers.stream()
.map(function)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
} finally {
lock.readLock().unlock();
}
private static Mono<Authentication> get(Function<AuthenticationSupplier, Mono<Authentication>> function) {
return Flux.concat(suppliers.stream()
.map(function)
.collect(Collectors.toList()))
.reduceWith(CompositeAuthentication::new, CompositeAuthentication::merge)
.filter(CompositeAuthentication::isNotEmpty)
.map(Authentication.class::cast);
}
/**
* @return 当前登录的用户权限信息
*/
public static Authentication get() {
String currentId = ThreadLocalUtils.get(CURRENT_USER_ID_KEY);
if (currentId != null) {
return get(currentId);
}
public static Mono<Authentication> get() {
return get(AuthenticationSupplier::get);
}
@@ -79,7 +74,7 @@ public final class AuthenticationHolder {
* @param userId 用户ID
* @return 权限信息
*/
public static Authentication get(String userId) {
public static Mono<Authentication> get(String userId) {
return get(supplier -> supplier.get(userId));
}
@@ -97,7 +92,4 @@ public final class AuthenticationHolder {
}
}
public static void setCurrentUserId(String id) {
ThreadLocalUtils.put(AuthenticationHolder.CURRENT_USER_ID_KEY, id);
}
}

View File

@@ -18,7 +18,7 @@
package org.hswebframework.web.authorization;
import org.hswebframework.web.authorization.listener.event.AuthorizationInitializeEvent;
import org.hswebframework.web.authorization.events.AuthorizationInitializeEvent;
/**
* 授权信息初始化服务接口,使用该接口初始化用的权限信息

View File

@@ -18,6 +18,8 @@
package org.hswebframework.web.authorization;
import reactor.core.publisher.Mono;
import java.io.Serializable;
import java.util.Map;
@@ -36,7 +38,7 @@ public interface AuthenticationManager {
* @param request 授权请求
* @return 授权成功则返回用户权限信息
*/
Authentication authenticate(AuthenticationRequest request);
Mono<Authentication> authenticate(AuthenticationRequest request);
/**
* 根据用户ID获取权限信息
@@ -44,7 +46,7 @@ public interface AuthenticationManager {
* @param userId 用户ID
* @return 权限信息
*/
Authentication getByUserId(String userId);
Mono<Authentication> getByUserId(String userId);
/**
* 同步授权信息,在调用了{@link Authentication#setAttribute(String, Serializable)}或者
@@ -56,5 +58,5 @@ public interface AuthenticationManager {
* @param authentication 要同步的权限信息
* @return 同步后的权限信息
*/
Authentication sync(Authentication authentication);
Mono<Authentication> sync(Authentication authentication);
}

View File

@@ -44,17 +44,7 @@ public interface AuthenticationPredicate extends Predicate<Authentication> {
return (t) -> test(t) || other.test(t);
}
default boolean test() {
return Authentication.current()
.map(this::test)
.orElse(false);
}
default void assertHas() {
if (!test()) {
throw new AccessDenyException();
}
}
default void assertHas(Authentication authentication) {
if (!test(authentication)) {

View File

@@ -17,6 +17,8 @@
package org.hswebframework.web.authorization;
import reactor.core.publisher.Mono;
import java.util.function.Supplier;
/**
@@ -25,6 +27,6 @@ import java.util.function.Supplier;
* @see Authentication
* @see AuthenticationHolder
*/
public interface AuthenticationSupplier extends Supplier<Authentication> {
Authentication get(String userId);
public interface AuthenticationSupplier extends Supplier<Mono<Authentication>> {
Mono<Authentication> get(String userId);
}

View File

@@ -0,0 +1,91 @@
package org.hswebframework.web.authorization;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
public class CompositeAuthentication implements Authentication {
private Map<String, Authentication> userAuthentication = new ConcurrentHashMap<>();
private String currentUser;
public boolean isEmpty() {
return userAuthentication.isEmpty();
}
public boolean isNotEmpty() {
return !isEmpty();
}
@Override
public User getUser() {
return userAuthentication
.get(currentUser)
.getUser();
}
@Override
public List<Role> getRoles() {
return userAuthentication.values()
.stream()
.map(Authentication::getRoles)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
@Override
public List<Permission> getPermissions() {
return userAuthentication.values()
.stream()
.map(Authentication::getPermissions)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
@Override
public <T extends Serializable> Optional<T> getAttribute(String name) {
return userAuthentication.values()
.stream()
.map(a -> a.<T>getAttribute(name))
.filter(Optional::isPresent)
.findAny()
.flatMap(Function.identity());
}
@Override
public void setAttribute(String name, Serializable object) {
}
@Override
public void setAttributes(Map<String, Serializable> attributes) {
}
@Override
public <T extends Serializable> T removeAttributes(String name) {
return null;
}
@Override
public Map<String, Serializable> getAttributes() {
return null;
}
public CompositeAuthentication merge(Authentication authentication) {
String userId = authentication.getUser().getId();
if (currentUser == null) {
currentUser = userId;
}
userAuthentication.put(userId, authentication);
return this;
}
}

View File

@@ -1,6 +1,6 @@
package org.hswebframework.web.authorization.define;
import org.hswebframework.web.authorization.listener.event.AuthorizationEvent;
import org.hswebframework.web.authorization.events.AuthorizationEvent;
import org.springframework.context.ApplicationEvent;
import java.util.List;

View File

@@ -16,7 +16,7 @@
*
*/
package org.hswebframework.web.authorization.listener.event;
package org.hswebframework.web.authorization.events;
import org.springframework.context.ApplicationEvent;

View File

@@ -16,7 +16,7 @@
*
*/
package org.hswebframework.web.authorization.listener.event;
package org.hswebframework.web.authorization.events;
import java.util.function.Function;

View File

@@ -16,7 +16,7 @@
*
*/
package org.hswebframework.web.authorization.listener.event;
package org.hswebframework.web.authorization.events;
import java.util.function.Function;

View File

@@ -16,7 +16,7 @@
*
*/
package org.hswebframework.web.authorization.listener.event;
package org.hswebframework.web.authorization.events;
import org.hswebframework.web.authorization.Authentication;
import org.springframework.context.ApplicationEvent;

View File

@@ -16,7 +16,7 @@
*
*/
package org.hswebframework.web.authorization.listener.event;
package org.hswebframework.web.authorization.events;
import java.util.function.Function;

View File

@@ -1,4 +1,4 @@
package org.hswebframework.web.authorization.listener.event;
package org.hswebframework.web.authorization.events;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -16,7 +16,7 @@
*
*/
package org.hswebframework.web.authorization.listener.event;
package org.hswebframework.web.authorization.events;
import org.hswebframework.web.authorization.Authentication;
import org.springframework.context.ApplicationEvent;

View File

@@ -1,4 +1,4 @@
package org.hswebframework.web.authorization.listener.event;
package org.hswebframework.web.authorization.events;
import org.hswebframework.web.authorization.define.AuthorizingContext;
import org.hswebframework.web.authorization.define.HandleType;

View File

@@ -1,6 +1,7 @@
package org.hswebframework.web.authorization.token;
import org.hswebframework.web.authorization.Authentication;
import reactor.core.publisher.Mono;
/**
* @author zhouhao
@@ -19,6 +20,6 @@ public interface ThirdPartAuthenticationManager {
* @param userId 用户ID
* @return 权限信息
*/
Authentication getByUserId(String userId);
Mono<Authentication> getByUserId(String userId);
}

View File

@@ -1,15 +1,16 @@
package org.hswebframework.web.authorization.token;
import org.hswebframework.web.ThreadLocalUtils;
import org.hswebframework.web.authorization.Authentication;
import org.hswebframework.web.authorization.AuthenticationManager;
import org.hswebframework.web.authorization.AuthenticationSupplier;
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
@@ -32,14 +33,14 @@ public class UserTokenAuthenticationSupplier implements AuthenticationSupplier {
}
@Override
public Authentication get(String userId) {
public Mono<Authentication> get(String userId) {
if (userId == null) {
return null;
}
return get(this.defaultAuthenticationManager, userId);
}
protected Authentication get(ThirdPartAuthenticationManager authenticationManager, String userId) {
protected Mono<Authentication> get(ThirdPartAuthenticationManager authenticationManager, String userId) {
if (null == userId) {
return null;
}
@@ -49,7 +50,7 @@ public class UserTokenAuthenticationSupplier implements AuthenticationSupplier {
return authenticationManager.getByUserId(userId);
}
protected Authentication get(AuthenticationManager authenticationManager, String userId) {
protected Mono<Authentication> get(AuthenticationManager authenticationManager, String userId) {
if (null == userId) {
return null;
}
@@ -59,19 +60,14 @@ public class UserTokenAuthenticationSupplier implements AuthenticationSupplier {
return authenticationManager.getByUserId(userId);
}
protected UserToken getCurrentUserToken() {
return UserTokenHolder.currentToken();
}
@Override
public Authentication get() {
return ThreadLocalUtils.get(Authentication.class.getName(), () ->
Optional.ofNullable(getCurrentUserToken())
.filter(UserToken::validate) //验证token,如果不是正常状态,将会抛出异常
.map(token ->
get(thirdPartAuthenticationManager
.get(token.getType()), token.getUserId())
)
.orElse(null));
public Mono<Authentication> get() {
return ContextUtils.currentContext()
.flatMap(context ->
context.get(ContextKey.of(UserToken.class))
.filter(UserToken::validate)
.map(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId()))
.orElseGet(Mono::empty));
}
}

View File

@@ -1,6 +1,6 @@
package org.hswebframework.web.authorization.token.event;
import org.hswebframework.web.authorization.listener.event.AuthorizationEvent;
import org.hswebframework.web.authorization.events.AuthorizationEvent;
import org.hswebframework.web.authorization.token.UserToken;
import org.springframework.context.ApplicationEvent;

View File

@@ -1,7 +1,7 @@
package org.hswebframework.web.authorization.token.event;
import org.hswebframework.web.authorization.token.UserToken;
import org.hswebframework.web.authorization.listener.event.AuthorizationEvent;
import org.hswebframework.web.authorization.events.AuthorizationEvent;
import org.springframework.context.ApplicationEvent;
public class UserTokenCreatedEvent extends ApplicationEvent implements AuthorizationEvent {

View File

@@ -1,6 +1,6 @@
package org.hswebframework.web.authorization.token.event;
import org.hswebframework.web.authorization.listener.event.AuthorizationEvent;
import org.hswebframework.web.authorization.events.AuthorizationEvent;
import org.hswebframework.web.authorization.token.UserToken;
import org.springframework.context.ApplicationEvent;

View File

@@ -1,17 +1,23 @@
package org.hswebframework.web.authorization;
import org.hswebframework.web.authorization.builder.AuthenticationBuilder;
import org.hswebframework.web.authorization.exception.AccessDenyException;
import org.hswebframework.web.authorization.exception.UnAuthorizedException;
import org.hswebframework.web.authorization.simple.builder.SimpleAuthenticationBuilder;
import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory;
import org.hswebframework.web.authorization.token.*;
import org.hswebframework.web.context.ContextKey;
import org.hswebframework.web.context.ContextUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.Collections;
import java.util.Set;
import static org.hswebframework.web.context.ContextUtils.*;
import static org.junit.Assert.*;
public class AuthenticationTests {
@@ -54,7 +60,7 @@ public class AuthenticationTests {
assertEquals(authentication.getPermissions().size(), 1);
assertTrue(authentication.hasPermission("user-manager"));
assertTrue(authentication.hasPermission("user-manager", "get"));
assertTrue(!authentication.hasPermission("user-manager", "delete"));
assertFalse(authentication.hasPermission("user-manager", "delete"));
boolean has = AuthenticationPredicate.has("permission:user-manager")
.or(AuthenticationPredicate.role("admin-role"))
@@ -95,21 +101,21 @@ public class AuthenticationTests {
//初始化权限管理器,用于获取用户的权限信息
AuthenticationManager authenticationManager = new AuthenticationManager() {
@Override
public Authentication authenticate(AuthenticationRequest request) {
public Mono<Authentication> authenticate(AuthenticationRequest request) {
return null;
}
@Override
public Authentication getByUserId(String userId) {
public Mono<Authentication> getByUserId(String userId) {
if (userId.equals("admin")) {
return authentication;
return Mono.just(authentication);
}
return null;
return Mono.empty();
}
@Override
public Authentication sync(Authentication authentication) {
return authentication;
public Mono<Authentication> sync(Authentication authentication) {
return Mono.just(authentication);
}
};
AuthenticationHolder.addSupplier(new UserTokenAuthenticationSupplier(authenticationManager));
@@ -117,11 +123,16 @@ public class AuthenticationTests {
//绑定用户token
UserTokenManager userTokenManager = new DefaultUserTokenManager();
UserToken token = userTokenManager.signIn("test", "token-test", "admin", -1);
UserTokenHolder.setCurrent(token);
//获取当前登录用户
Authentication current = Authentication.current().orElseThrow(UnAuthorizedException::new);
Assert.assertEquals(current.getUser().getId(), "admin");
Authentication
.current()
.map(Authentication::getUser)
.map(User::getId)
.subscriberContext(acceptContext(ctx->ctx.put(ContextKey.of(UserToken.class),token)))
.as(StepVerifier::create)
.expectNext("admin")
.verifyComplete();
}