feat:实现全异步改造
This commit is contained in:
parent
72550ab68e
commit
a5ffeae42f
@ -0,0 +1,24 @@
|
||||
package com.flyfish.framework.auditor;
|
||||
|
||||
import com.flyfish.framework.context.UserContext;
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedDomain;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AuthorizeAuditor implements BeanAuditor<AuthorizedDomain> {
|
||||
|
||||
private final UserContext userContext;
|
||||
|
||||
/**
|
||||
* 对实体进行审查,并补全相关字段
|
||||
*
|
||||
* @param data 原数据
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public void audit(AuthorizedDomain data) {
|
||||
data.setAuthorizeId(userContext.currentUser().getAuthority());
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.flyfish.framework.auditor;
|
||||
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedDomain;
|
||||
import com.flyfish.framework.domain.base.IUser;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ReactiveAuthorizeAuditor implements ReactiveBeanAuditor<AuthorizedDomain> {
|
||||
|
||||
/**
|
||||
* 对实体进行审查,并补全相关字段
|
||||
*
|
||||
* @param data 原数据
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Mono<AuthorizedDomain> audit(AuthorizedDomain data) {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(ctx -> (IUser) ctx.getAuthentication().getPrincipal())
|
||||
.map(user -> {
|
||||
data.setAuthorizeId(user.getAuthority());
|
||||
return data;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.flyfish.framework.domain.authorized;
|
||||
|
||||
import com.flyfish.framework.builder.CriteriaBuilder;
|
||||
import com.flyfish.framework.domain.base.NameLikeQo;
|
||||
import com.flyfish.framework.domain.po.Department;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 带鉴权的查询实体,主要以部门隔绝
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class AuthorizedQo<T extends AuthorizedDomain> extends NameLikeQo<T> {
|
||||
|
||||
/**
|
||||
* 获取可见的权限ids
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public List<String> getAuthorizedIds() {
|
||||
if (user instanceof AuthorizedUserDetails) {
|
||||
return ((AuthorizedUserDetails) user).getAuthorityCodes();
|
||||
}
|
||||
return Collections.singletonList(Department.PUBLIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CriteriaBuilder<T> criteriaBuilder() {
|
||||
return super.criteriaBuilder().with("authorizedIds", "authorizeId", CriteriaBuilder.Builders.IN);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.flyfish.framework.domain.authorized;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支持授权的用户详情
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
public interface AuthorizedUserDetails {
|
||||
|
||||
/**
|
||||
* 获取授权codes
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
List<String> getAuthorityCodes();
|
||||
}
|
@ -2,7 +2,6 @@ package com.flyfish.framework.domain.base;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.flyfish.framework.builder.CriteriaBuilder;
|
||||
import com.flyfish.framework.domain.po.User;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@ -22,7 +21,7 @@ public class BaseQo<T extends Domain> implements Qo<T> {
|
||||
|
||||
protected List<T> result;
|
||||
|
||||
protected User user;
|
||||
protected IUser user;
|
||||
|
||||
public Qo<T> accept(List<T> result, Pageable pageable) {
|
||||
this.pageable = pageable;
|
||||
@ -52,7 +51,7 @@ public class BaseQo<T extends Domain> implements Qo<T> {
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public User getUser() {
|
||||
public IUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@ -62,7 +61,7 @@ public class BaseQo<T extends Domain> implements Qo<T> {
|
||||
* @param user 用户数据
|
||||
*/
|
||||
@Override
|
||||
public void setUser(User user) {
|
||||
public void setUser(IUser user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
|
@ -36,12 +36,12 @@ public interface Qo<T> {
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
User getUser();
|
||||
IUser getUser();
|
||||
|
||||
/**
|
||||
* 当前用户
|
||||
*/
|
||||
void setUser(User user);
|
||||
void setUser(IUser user);
|
||||
|
||||
/**
|
||||
* 获取结果集,用于单例部署时快速封装
|
||||
|
@ -5,7 +5,7 @@ import com.flyfish.framework.domain.po.User;
|
||||
import com.flyfish.framework.enums.UserStatus;
|
||||
import com.flyfish.framework.service.AuthenticationAuditor;
|
||||
import com.flyfish.framework.service.AuthenticationLogger;
|
||||
import com.flyfish.framework.service.ReactiveUserService;
|
||||
import com.flyfish.framework.service.UserService;
|
||||
import com.flyfish.framework.transform.ResultDataTransformer;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@ -24,7 +24,7 @@ import java.util.Date;
|
||||
public class AuthenticationAuditorImpl extends ResultDataTransformer implements AuthenticationAuditor {
|
||||
|
||||
@Resource
|
||||
private ReactiveUserService reactiveUserService;
|
||||
private UserService userService;
|
||||
@Resource
|
||||
private AuthenticationLogger authenticationLogger;
|
||||
|
||||
@ -40,7 +40,7 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements
|
||||
updating.setId(details.getId());
|
||||
updating.setErrorCount(0);
|
||||
updating.setLastTime(new Date());
|
||||
return reactiveUserService.updateSelectiveById(updating).then(authenticationLogger.success(user));
|
||||
return userService.updateSelectiveById(updating).then(authenticationLogger.success(user));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,7 +56,7 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements
|
||||
.getFormData()
|
||||
.flatMap(data -> {
|
||||
String username = data.getFirst("username");
|
||||
Mono<User> userMono = reactiveUserService.findByUsername(username).defaultIfEmpty(emptyUser(username));
|
||||
Mono<User> userMono = userService.findByUsername(username).defaultIfEmpty(emptyUser(username));
|
||||
// 当且仅当为凭据错误,尝试
|
||||
if (exception instanceof BadCredentialsException) {
|
||||
userMono = userMono.flatMap(user -> {
|
||||
@ -66,7 +66,7 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements
|
||||
if (updating.getErrorCount() >= 5) {
|
||||
updating.setStatus(UserStatus.LOCKED);
|
||||
}
|
||||
return reactiveUserService.updateSelectiveById(updating);
|
||||
return userService.updateSelectiveById(updating);
|
||||
});
|
||||
}
|
||||
return userMono.flatMap(user -> authenticationLogger.failure(user, exception));
|
||||
|
@ -14,7 +14,7 @@ import com.flyfish.framework.handler.JsonLogoutSuccessHandler;
|
||||
import com.flyfish.framework.initializer.UserInitializer;
|
||||
import com.flyfish.framework.service.AuthenticationAuditor;
|
||||
import com.flyfish.framework.service.AuthenticationLogger;
|
||||
import com.flyfish.framework.service.ReactiveUserService;
|
||||
import com.flyfish.framework.service.UserService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@ -166,7 +166,7 @@ public class WebSecurityConfig {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(UserInitializer.class)
|
||||
@SuppressWarnings("all")
|
||||
public UserInitializer userInitializer(ReactiveUserService userService) {
|
||||
public UserInitializer userInitializer(UserService userService) {
|
||||
return () -> {
|
||||
UserQo qo = new UserQo();
|
||||
qo.setType(UserType.SUPER_ADMIN.name());
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.flyfish.framework.config.audit;
|
||||
|
||||
import com.flyfish.framework.domain.base.Domain;
|
||||
import com.flyfish.framework.utils.UserUtils;
|
||||
import org.springframework.data.domain.ReactiveAuditorAware;
|
||||
import org.springframework.lang.NonNull;
|
||||
@ -25,8 +24,7 @@ public class ReactiveUserAuditor implements ReactiveAuditorAware<String> {
|
||||
@NonNull
|
||||
public Mono<String> getCurrentAuditor() {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(UserUtils::extractUser)
|
||||
.map(Domain::getName)
|
||||
.map(UserUtils::extractUserName)
|
||||
.defaultIfEmpty("匿名用户");
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import com.flyfish.framework.auditor.ReactiveBeanPoster;
|
||||
import com.flyfish.framework.config.constants.UserCacheKeys;
|
||||
import com.flyfish.framework.domain.po.User;
|
||||
import com.flyfish.framework.enums.UserType;
|
||||
import com.flyfish.framework.service.UserDetailsConverter;
|
||||
import com.flyfish.framework.utils.Assert;
|
||||
import com.flyfish.framework.utils.ReactiveRedisOperations;
|
||||
import com.flyfish.framework.utils.StrengthUtils;
|
||||
@ -20,6 +21,7 @@ public class UserBeanAuditor implements ReactiveBeanAuditor<User>, ReactiveBeanP
|
||||
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final ReactiveRedisOperations reactiveRedisOperations;
|
||||
private final UserDetailsConverter userDetailsConverter;
|
||||
|
||||
/**
|
||||
* 对实体进行审查,并补全相关字段
|
||||
@ -55,6 +57,7 @@ public class UserBeanAuditor implements ReactiveBeanAuditor<User>, ReactiveBeanP
|
||||
@Override
|
||||
public Mono<User> post(User data) {
|
||||
// 更新缓存
|
||||
return reactiveRedisOperations.del(UserCacheKeys.get(data.getUsername())).then(Mono.just(data));
|
||||
return reactiveRedisOperations.set(UserCacheKeys.get(data.getUsername()),
|
||||
userDetailsConverter.mapToUserDetails(data)).then(Mono.just(data));
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,10 @@ import com.flyfish.framework.domain.base.IUser;
|
||||
import com.flyfish.framework.domain.po.Role;
|
||||
import com.flyfish.framework.domain.po.User;
|
||||
import com.flyfish.framework.enums.UserStatus;
|
||||
import com.flyfish.framework.service.ReactiveUserService;
|
||||
import com.flyfish.framework.service.UserService;
|
||||
import com.flyfish.framework.utils.Assert;
|
||||
import com.flyfish.framework.utils.StrengthUtils;
|
||||
import com.flyfish.framework.utils.UserUtils;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -84,21 +85,20 @@ public class UserController extends ReactiveBaseController<User, UserQo> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户状态,主要更新部门
|
||||
* 更新用户状态,主要更新部门,同时更新缓存
|
||||
*
|
||||
* @param authorize 鉴权
|
||||
* @return 结果
|
||||
*/
|
||||
@PatchMapping("/status")
|
||||
public Mono<Result<User>> updateStatus(String authorize) {
|
||||
ReactiveUserService reactiveService = (ReactiveUserService) this.reactiveService;
|
||||
UserService reactiveService = (UserService) this.reactiveService;
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(context -> (IUser) context.getAuthentication().getPrincipal())
|
||||
.map(UserUtils::extractUserDetails)
|
||||
.flatMap(user -> {
|
||||
user.setAuthority(authorize);
|
||||
User updating = new User();
|
||||
updating.setId(user.getId());
|
||||
updating.setAuthority(user.getAuthority());
|
||||
updating.setAuthority(authorize);
|
||||
return reactiveService.updateSelectiveById(updating);
|
||||
})
|
||||
.map(Result::ok);
|
||||
|
@ -0,0 +1,125 @@
|
||||
package com.flyfish.framework.controller.authorized;
|
||||
|
||||
import com.flyfish.framework.annotations.Operation;
|
||||
import com.flyfish.framework.bean.Result;
|
||||
import com.flyfish.framework.bean.SyncVo;
|
||||
import com.flyfish.framework.configuration.annotations.CurrentUser;
|
||||
import com.flyfish.framework.configuration.annotations.PagedQuery;
|
||||
import com.flyfish.framework.configuration.annotations.ValidRequestBody;
|
||||
import com.flyfish.framework.constant.ReactiveConstants;
|
||||
import com.flyfish.framework.context.UserContext;
|
||||
import com.flyfish.framework.controller.SafeController;
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedDomain;
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedQo;
|
||||
import com.flyfish.framework.domain.po.User;
|
||||
import com.flyfish.framework.service.BaseReactiveService;
|
||||
import com.flyfish.framework.service.BaseService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用RESTful的控制器,用于动态提供基础的RESTful接口
|
||||
*
|
||||
* @author wangyu
|
||||
* @create 2017-06-15 8:48
|
||||
*/
|
||||
public abstract class AuthorizedController<T extends AuthorizedDomain, Q extends AuthorizedQo<T>> implements SafeController {
|
||||
|
||||
@Autowired
|
||||
protected BaseService<T> service;
|
||||
@Autowired(required = false)
|
||||
protected BaseReactiveService<T> reactiveService;
|
||||
@Autowired
|
||||
protected UserContext userContext;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends BaseService<T>> S getService() {
|
||||
return (S) service;
|
||||
}
|
||||
|
||||
@GetMapping("/exists")
|
||||
public Result<Boolean> exists(@PagedQuery Q qo) {
|
||||
return Result.accept(service.count(qo) != 0);
|
||||
}
|
||||
|
||||
@GetMapping("/count")
|
||||
public Result<Long> count(@PagedQuery Q qo) {
|
||||
return Result.accept(service.count(qo));
|
||||
}
|
||||
|
||||
@PostMapping("")
|
||||
@Operation.Create
|
||||
public Result<T> create(@ValidRequestBody T entity, @CurrentUser User user) {
|
||||
userContext.setUser(user);
|
||||
return Result.accept(service.create(entity));
|
||||
}
|
||||
|
||||
@GetMapping("{id}")
|
||||
public Result<T> get(@PathVariable String id) {
|
||||
return service.getById(id).map(Result::accept).orElse(Result.notFound());
|
||||
}
|
||||
|
||||
@PutMapping("{id}")
|
||||
@Operation.Update
|
||||
public Result<T> update(@ValidRequestBody T entity, @CurrentUser User user) {
|
||||
userContext.setUser(user);
|
||||
return Result.accept(service.updateSelectiveById(entity));
|
||||
}
|
||||
|
||||
@PatchMapping("{id}")
|
||||
@Operation.Update
|
||||
public Result<T> patch(@RequestBody T entity, @CurrentUser User user) {
|
||||
userContext.setUser(user);
|
||||
return Result.accept(service.updateSelectiveById(entity));
|
||||
}
|
||||
|
||||
@PutMapping("")
|
||||
@Operation.UpdateAll
|
||||
public Result<List<T>> updateList(@RequestBody List<T> list, @CurrentUser User user) {
|
||||
userContext.setUser(user);
|
||||
return Result.accept(service.updateBatch(list));
|
||||
}
|
||||
|
||||
@PutMapping("/sync")
|
||||
@Operation.Sync
|
||||
public Result<SyncVo<T>> syncList(@RequestBody List<T> list, @CurrentUser User user) {
|
||||
userContext.setUser(user);
|
||||
return Result.accept(service.sync(list));
|
||||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@Operation.Delete
|
||||
public Result<T> remove(@PathVariable List<String> id, @CurrentUser User user) {
|
||||
userContext.setUser(user);
|
||||
service.deleteBatchByIds(id);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/all")
|
||||
public Result<List<T>> all(@PagedQuery Q qo) {
|
||||
if (qo.isEmpty()) {
|
||||
return Result.accept(service.getAll());
|
||||
}
|
||||
return Result.accept(service.getList(qo));
|
||||
}
|
||||
|
||||
@GetMapping("")
|
||||
public Result<List<T>> list(@PagedQuery Q qo) {
|
||||
if (null != qo.getPageable()) {
|
||||
return Result.accept(service.getPageList(qo));
|
||||
}
|
||||
return Result.accept(service.getList(qo));
|
||||
}
|
||||
|
||||
|
||||
@PutMapping(value = "{id}", headers = ReactiveConstants.USE_REACTIVE)
|
||||
public Mono<Result<T>> reactiveUpdate(@ValidRequestBody T entity) {
|
||||
return reactiveService.updateById(entity)
|
||||
.map(Result::accept)
|
||||
.defaultIfEmpty(Result.notFound());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package com.flyfish.framework.controller.authorized;
|
||||
|
||||
import com.flyfish.framework.annotations.Operation;
|
||||
import com.flyfish.framework.bean.Result;
|
||||
import com.flyfish.framework.bean.SyncVo;
|
||||
import com.flyfish.framework.configuration.annotations.PagedQuery;
|
||||
import com.flyfish.framework.configuration.annotations.ValidRequestBody;
|
||||
import com.flyfish.framework.controller.SafeController;
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedDomain;
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedQo;
|
||||
import com.flyfish.framework.service.BaseReactiveService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.util.CastUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 多租户带授权的控制器
|
||||
*
|
||||
* @param <T> 实体泛型
|
||||
* @param <Q> 查询实体泛型
|
||||
*/
|
||||
public abstract class ReactiveAuthorizedController<T extends AuthorizedDomain, Q extends AuthorizedQo<T>> implements SafeController {
|
||||
|
||||
@Autowired
|
||||
protected BaseReactiveService<T> reactiveService;
|
||||
|
||||
public <S extends BaseReactiveService<T>> S getService() {
|
||||
return CastUtils.cast(reactiveService);
|
||||
}
|
||||
|
||||
@GetMapping("/exists")
|
||||
public Mono<Result<Boolean>> exists(@PagedQuery Q qo) {
|
||||
return reactiveService.exists(qo).map(Result::accept);
|
||||
}
|
||||
|
||||
@GetMapping("/count")
|
||||
public Mono<Result<Long>> count(@PagedQuery Q qo) {
|
||||
return reactiveService.count(qo).map(Result::accept);
|
||||
}
|
||||
|
||||
@PostMapping("")
|
||||
@Operation.Create
|
||||
public Mono<Result<T>> create(@ValidRequestBody T entity) {
|
||||
return reactiveService.create(entity).map(Result::accept);
|
||||
}
|
||||
|
||||
@GetMapping("{id}")
|
||||
public Mono<Result<T>> get(@PathVariable String id) {
|
||||
return reactiveService.getById(id).map(Result::accept).defaultIfEmpty(Result.notFound());
|
||||
}
|
||||
|
||||
@PutMapping("{id}")
|
||||
@Operation.Update
|
||||
public Mono<Result<T>> update(@ValidRequestBody T entity) {
|
||||
return reactiveService.updateSelectiveById(entity).map(Result::accept).defaultIfEmpty(Result.notFound());
|
||||
}
|
||||
|
||||
@PatchMapping("{id}")
|
||||
@Operation.Update
|
||||
public Mono<Result<T>> patch(@RequestBody T entity) {
|
||||
return reactiveService.updateSelectiveById(entity).map(Result::accept).defaultIfEmpty(Result.notFound());
|
||||
}
|
||||
|
||||
@PutMapping("")
|
||||
@Operation.UpdateAll
|
||||
public Mono<Result<List<T>>> updateList(@RequestBody List<T> list) {
|
||||
return reactiveService.updateBatch(list).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList());
|
||||
}
|
||||
|
||||
@PutMapping("/sync")
|
||||
@Operation.Sync
|
||||
public Mono<Result<SyncVo<T>>> syncList(@RequestBody List<T> list) {
|
||||
return reactiveService.sync(list).map(Result::accept).defaultIfEmpty(Result.accept(SyncVo.<T>builder().build()));
|
||||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@Operation.Delete
|
||||
public Mono<Result<T>> remove(@PathVariable List<String> id) {
|
||||
return reactiveService.deleteBatchByIds(id).thenReturn(Result.ok());
|
||||
}
|
||||
|
||||
@GetMapping("/all")
|
||||
public Mono<Result<List<T>>> all(@PagedQuery Q qo) {
|
||||
if (qo.isEmpty()) {
|
||||
return reactiveService.getAll().collectList().map(Result::accept).defaultIfEmpty(Result.emptyList());
|
||||
}
|
||||
return reactiveService.getList(qo).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList());
|
||||
}
|
||||
|
||||
@GetMapping("")
|
||||
public Mono<Result<List<T>>> list(@PagedQuery Q qo) {
|
||||
if (null != qo.getPageable() && qo.getPageable().isPaged()) {
|
||||
return reactiveService.getPageList(qo).map(Result::accept).defaultIfEmpty(Result.emptyPage());
|
||||
}
|
||||
return reactiveService.getList(qo).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList());
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package com.flyfish.framework.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedUserDetails;
|
||||
import com.flyfish.framework.domain.base.Domain;
|
||||
import com.flyfish.framework.domain.base.IUser;
|
||||
import com.flyfish.framework.domain.po.Department;
|
||||
@ -30,7 +31,7 @@ import java.util.List;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class AdminUserDetails implements UserDetails, IUser {
|
||||
public class AdminUserDetails implements UserDetails, IUser, AuthorizedUserDetails {
|
||||
|
||||
private static final long serialVersionUID = -2441854985340378429L;
|
||||
|
||||
@ -101,6 +102,10 @@ public class AdminUserDetails implements UserDetails, IUser {
|
||||
* 查询冗余,标记用户信息
|
||||
*/
|
||||
private Object detail;
|
||||
/**
|
||||
* 权限code列表
|
||||
*/
|
||||
private List<String> authorityCodes;
|
||||
|
||||
/**
|
||||
* 判断是否是管理员
|
||||
|
@ -1,64 +0,0 @@
|
||||
package com.flyfish.framework.domain.authorized;
|
||||
|
||||
import com.flyfish.framework.builder.CriteriaBuilder;
|
||||
import com.flyfish.framework.context.SpringContext;
|
||||
import com.flyfish.framework.domain.base.NameLikeQo;
|
||||
import com.flyfish.framework.domain.po.Department;
|
||||
import com.flyfish.framework.enums.UserType;
|
||||
import com.flyfish.framework.service.DepartmentService;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.val;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 带鉴权的查询实体,主要以部门隔绝
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class AuthorizedQo<T extends AuthorizedDomain> extends NameLikeQo<T> {
|
||||
|
||||
// 部门服务
|
||||
private DepartmentService departmentService;
|
||||
|
||||
/**
|
||||
* 获取可见的权限ids
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public List<String> getAuthorizedIds() {
|
||||
if (null != user) {
|
||||
// 是超级管理员,放行,返回null
|
||||
if (user.getType() == UserType.SUPER_ADMIN) {
|
||||
return null;
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(user.getDepartments())) {
|
||||
val departs = user.getDepartments().stream().map(Department::getId)
|
||||
.collect(Collectors.toList());
|
||||
val result = getSubAuthorities(departs);
|
||||
if (CollectionUtils.isNotEmpty(result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.singletonList(Department.PUBLIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CriteriaBuilder<T> criteriaBuilder() {
|
||||
return super.criteriaBuilder().with("authorizedIds", "authorizeId", CriteriaBuilder.Builders.IN);
|
||||
}
|
||||
|
||||
private List<String> getSubAuthorities(List<String> parents) {
|
||||
if (null == departmentService) {
|
||||
departmentService = SpringContext.getBean(DepartmentService.class);
|
||||
}
|
||||
return departmentService.getSubCodes(parents);
|
||||
}
|
||||
}
|
@ -2,14 +2,14 @@ package com.flyfish.framework.service;
|
||||
|
||||
import com.flyfish.framework.domain.po.Department;
|
||||
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 部门服务
|
||||
@ -20,17 +20,16 @@ import java.util.stream.Collectors;
|
||||
public class DepartmentService extends BaseReactiveServiceImpl<Department> {
|
||||
|
||||
@Resource
|
||||
private MongoOperations mongoOperations;
|
||||
private ReactiveMongoOperations reactiveMongoOperations;
|
||||
|
||||
/**
|
||||
* 获取子部门列表
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public List<String> getSubCodes(List<String> parents) {
|
||||
public Mono<List<String>> getSubCodes(List<String> parents) {
|
||||
Query query = Query.query(Criteria.where("parentId").in(parents));
|
||||
query.fields().include("_id");
|
||||
return mongoOperations.find(query, Department.class).stream().map(Department::getId)
|
||||
.collect(Collectors.toList());
|
||||
return reactiveMongoOperations.find(query, Department.class).map(Department::getId).collectList();
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
package com.flyfish.framework.service;
|
||||
|
||||
import com.flyfish.framework.config.constants.UserCacheKeys;
|
||||
import com.flyfish.framework.domain.AdminUserDetails;
|
||||
import com.flyfish.framework.domain.base.IUser;
|
||||
import com.flyfish.framework.domain.po.User;
|
||||
import com.flyfish.framework.enums.UserStatus;
|
||||
import com.flyfish.framework.utils.Assert;
|
||||
import com.flyfish.framework.utils.CopyUtils;
|
||||
import com.flyfish.framework.utils.ReactiveRedisOperations;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
@ -52,7 +50,8 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService {
|
||||
() -> new LockedException("账户已经锁定!请联系管理员修改密码!"));
|
||||
}
|
||||
|
||||
private final ReactiveUserService userService;
|
||||
private final UserService userService;
|
||||
private final UserDetailsConverter userDetailsConverter;
|
||||
|
||||
@Resource
|
||||
private ServerSecurityContextRepository contextRepository;
|
||||
@ -72,27 +71,23 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UserDetails> updatePassword(UserDetails userDetails, String s) {
|
||||
return userService.updateById(((IUser) userDetails).toUser()).map(this::mapToUserDetails);
|
||||
public Mono<UserDetails> updatePassword(UserDetails userDetails, String password) {
|
||||
return userService.updateById(((IUser) userDetails).toUser()).thenReturn(userDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UserDetails> findByUsername(String s) {
|
||||
String key = UserCacheKeys.get(s);
|
||||
public Mono<UserDetails> findByUsername(String username) {
|
||||
String key = UserCacheKeys.get(username);
|
||||
// 优先从缓存读取,如果缓存不存在,查询转换后放入缓存
|
||||
return reactiveRedisOperations.hasKey(key).flatMap(exists -> Boolean.TRUE.equals(exists) ? reactiveRedisOperations.get(key) :
|
||||
userService.findByUsername(s).flatMap(this::validate).map(this::mapToUserDetails)
|
||||
userService.findByUsername(username)
|
||||
.flatMap(this::validate)
|
||||
.flatMap(userDetailsConverter::mapToUserDetails)
|
||||
.flatMap(detail -> reactiveRedisOperations.set(key, detail).thenReturn(detail))
|
||||
)
|
||||
.switchIfEmpty(Mono.defer(() -> Mono.error(new UsernameNotFoundException("用户不存在!"))));
|
||||
}
|
||||
|
||||
private UserDetails mapToUserDetails(IUser user) {
|
||||
AdminUserDetails userDetail = new AdminUserDetails();
|
||||
CopyUtils.copyProps(user, userDetail);
|
||||
return userDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验
|
||||
*
|
||||
@ -117,7 +112,7 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService {
|
||||
public Mono<Authentication> authenticate(UserDetails user, ServerWebExchange exchange) {
|
||||
return loadContext(user)
|
||||
.flatMap(securityContext -> contextRepository.save(exchange, securityContext)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withSecurityContext(
|
||||
.contextWrite(ReactiveSecurityContextHolder.withSecurityContext(
|
||||
Mono.just(securityContext)))
|
||||
.then(Mono.just(securityContext)))
|
||||
.map(SecurityContext::getAuthentication)
|
||||
@ -156,4 +151,5 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService {
|
||||
.flatMap(context -> contextRepository.save(exchange, context));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
package com.flyfish.framework.service;
|
||||
|
||||
import com.flyfish.framework.domain.po.User;
|
||||
import com.flyfish.framework.repository.ReactiveUserRepository;
|
||||
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 异步用户service
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
@Service
|
||||
public class ReactiveUserService extends BaseReactiveServiceImpl<User> implements UserFindService {
|
||||
|
||||
/**
|
||||
* 获取用户数据
|
||||
*
|
||||
* @param username 用户
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Mono<User> findByUsername(String username) {
|
||||
return ((ReactiveUserRepository) repository).findByUsername(username);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.flyfish.framework.service;
|
||||
|
||||
import com.flyfish.framework.domain.AdminUserDetails;
|
||||
import com.flyfish.framework.domain.base.IUser;
|
||||
import com.flyfish.framework.domain.po.Department;
|
||||
import com.flyfish.framework.enums.UserType;
|
||||
import com.flyfish.framework.utils.CopyUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserDetailsConverter {
|
||||
|
||||
private final DepartmentService departmentService;
|
||||
|
||||
/**
|
||||
* 将用户映射为用户详情,查询所有权限code
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @return 结果
|
||||
*/
|
||||
public Mono<UserDetails> mapToUserDetails(IUser user) {
|
||||
AdminUserDetails userDetail = new AdminUserDetails();
|
||||
CopyUtils.copyProps(user, userDetail);
|
||||
userDetail.setAuthorityCodes(Collections.singletonList(Department.PUBLIC));
|
||||
if (user.getType() == UserType.SUPER_ADMIN) {
|
||||
userDetail.setAuthorityCodes(null);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(user.getDepartments())) {
|
||||
val departs = user.getDepartments().stream().map(Department::getId)
|
||||
.collect(Collectors.toList());
|
||||
return departmentService.getSubCodes(departs)
|
||||
.map(codes -> {
|
||||
if (CollectionUtils.isNotEmpty(codes)) {
|
||||
userDetail.setAuthorityCodes(ListUtils.union(codes, userDetail.getAuthorityCodes()));
|
||||
}
|
||||
return userDetail;
|
||||
});
|
||||
}
|
||||
return Mono.just(userDetail);
|
||||
}
|
||||
}
|
@ -1,10 +1,28 @@
|
||||
package com.flyfish.framework.service;
|
||||
|
||||
import com.flyfish.framework.domain.po.User;
|
||||
import com.flyfish.framework.service.impl.BaseServiceImpl;
|
||||
import com.flyfish.framework.repository.ReactiveUserRepository;
|
||||
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 异步用户service
|
||||
*
|
||||
* @author wangyu
|
||||
*/
|
||||
@Service
|
||||
public class UserService extends BaseServiceImpl<User> {
|
||||
public class UserService extends BaseReactiveServiceImpl<User> implements UserFindService {
|
||||
|
||||
/**
|
||||
* 获取用户数据
|
||||
*
|
||||
* @param username 用户
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Mono<User> findByUsername(String username) {
|
||||
return ((ReactiveUserRepository) repository).findByUsername(username);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,4 +13,5 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PagedQuery {
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import com.flyfish.framework.utils.UserUtils;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.util.CastUtils;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
|
||||
@ -29,6 +30,7 @@ public class PageQueryArgumentResolver extends HandlerMethodArgumentResolverSupp
|
||||
*/
|
||||
private ModelAttributeFilter modelAttributeFilter;
|
||||
|
||||
|
||||
public PageQueryArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
|
||||
super(adapterRegistry);
|
||||
this.pageableParameterFilter = new PageParameterFilter();
|
||||
@ -56,14 +58,14 @@ public class PageQueryArgumentResolver extends HandlerMethodArgumentResolverSupp
|
||||
// 使用spring的默认解析器解析所有变量
|
||||
return modelAttributeFilter.filter(parameter, bindingContext, exchange).flatMap(qo -> {
|
||||
if (qo instanceof Qo) {
|
||||
Qo query = (Qo) qo;
|
||||
Qo<?> query = (Qo<?>) qo;
|
||||
query.setPageable(pageable);
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(UserUtils::extractUser)
|
||||
.map(UserUtils::extractUserDetails)
|
||||
.map(user -> {
|
||||
query.setUser(user);
|
||||
return query;
|
||||
}).defaultIfEmpty(query);
|
||||
}).defaultIfEmpty(CastUtils.cast(query));
|
||||
}
|
||||
return Mono.just(qo);
|
||||
});
|
||||
|
@ -3,6 +3,7 @@ package com.flyfish.framework.service.impl;
|
||||
import com.flyfish.framework.auditor.ReactiveBeanAuditor;
|
||||
import com.flyfish.framework.auditor.ReactiveBeanPoster;
|
||||
import com.flyfish.framework.bean.SyncVo;
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedDomain;
|
||||
import com.flyfish.framework.domain.base.AuditDomain;
|
||||
import com.flyfish.framework.domain.base.Domain;
|
||||
import com.flyfish.framework.domain.base.Qo;
|
||||
@ -42,6 +43,8 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
|
||||
protected ReactiveBeanPoster<T> poster;
|
||||
@Autowired
|
||||
private ReactiveBeanAuditor<AuditDomain> operationAuditor;
|
||||
@Autowired
|
||||
private ReactiveBeanAuditor<AuthorizedDomain> authorizeAuditor;
|
||||
|
||||
/**
|
||||
* 查询
|
||||
@ -369,15 +372,20 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
|
||||
* @param entity 实体
|
||||
*/
|
||||
protected Mono<T> audit(T entity) {
|
||||
// 用户审查
|
||||
if (entity instanceof AuditDomain) {
|
||||
return CastUtils.cast(operationAuditor.audit((AuditDomain) entity));
|
||||
}
|
||||
// 自定义审查
|
||||
Mono<T> mono = Mono.just(entity);
|
||||
// 首先自定义审查,可能返回自定义对象
|
||||
if (auditor != null) {
|
||||
return auditor.audit(entity);
|
||||
mono = mono.flatMap(auditor::audit);
|
||||
}
|
||||
return Mono.just(entity);
|
||||
// 操作信息审查
|
||||
if (entity instanceof AuditDomain) {
|
||||
mono = CastUtils.cast(mono.cast(AuditDomain.class).flatMap(operationAuditor::audit));
|
||||
}
|
||||
// 权限审查
|
||||
if (entity instanceof AuthorizedDomain) {
|
||||
mono = CastUtils.cast(mono.cast(AuthorizedDomain.class).flatMap(authorizeAuditor::audit));
|
||||
}
|
||||
return mono;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,7 @@ package com.flyfish.framework.service.impl;
|
||||
import com.flyfish.framework.auditor.BeanAuditor;
|
||||
import com.flyfish.framework.auditor.BeanPoster;
|
||||
import com.flyfish.framework.bean.SyncVo;
|
||||
import com.flyfish.framework.domain.authorized.AuthorizedDomain;
|
||||
import com.flyfish.framework.domain.base.AuditDomain;
|
||||
import com.flyfish.framework.domain.base.Domain;
|
||||
import com.flyfish.framework.domain.base.Qo;
|
||||
@ -35,6 +36,8 @@ public class BaseServiceImpl<T extends Domain> implements BaseService<T> {
|
||||
protected BeanPoster<T> poster;
|
||||
@Autowired
|
||||
private BeanAuditor<AuditDomain> operationAuditor;
|
||||
@Autowired
|
||||
private BeanAuditor<AuthorizedDomain> authorizeAuditor;
|
||||
|
||||
/**
|
||||
* 查询
|
||||
@ -341,13 +344,17 @@ public class BaseServiceImpl<T extends Domain> implements BaseService<T> {
|
||||
* @param entity 实体
|
||||
*/
|
||||
protected void audit(T entity) {
|
||||
// 自定义审查
|
||||
if (auditor != null) {
|
||||
auditor.audit(entity);
|
||||
}
|
||||
// 用户审查
|
||||
if (entity instanceof AuditDomain) {
|
||||
operationAuditor.audit((AuditDomain) entity);
|
||||
}
|
||||
// 自定义审查
|
||||
if (auditor != null) {
|
||||
auditor.audit(entity);
|
||||
// 权限审查
|
||||
if (entity instanceof AuthorizedDomain) {
|
||||
authorizeAuditor.audit((AuthorizedDomain) entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,26 @@ public class UserUtils {
|
||||
return ((IUser) securityContext.getAuthentication().getPrincipal()).toUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压用户详情
|
||||
*
|
||||
* @param securityContext 上下文
|
||||
* @return 结果
|
||||
*/
|
||||
public static IUser extractUserDetails(SecurityContext securityContext) {
|
||||
return (IUser) securityContext.getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压用户名称
|
||||
*
|
||||
* @param securityContext 上下文
|
||||
* @return 结果
|
||||
*/
|
||||
public static String extractUserName(SecurityContext securityContext) {
|
||||
return ((IUser) securityContext.getAuthentication().getPrincipal()).getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换用户
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user