Skip to content

Commit

Permalink
✨ feat(`boot/platform/src/main/java/com/plate/boot/security/core/User…
Browse files Browse the repository at this point in the history
…Auditor.java`): 在 `UserAuditor` 类中添加了 `getCurrentAuditor` 方法,用于获取当前用户的审计信息。

✨ feat(`boot/platform/src/main/java/com/plate/boot/commons/utils/query/QueryHelper.java`): 在 `QueryHelper` 类中添加了对查询条件的处理,支持字符串类型的查询条件。

✨ feat(`boot/platform/src/main/java/com/plate/boot/security/core/UserAuditor.java`): 在 `UserAuditor` 类中添加了 `of` 方法,用于创建 `UserAuditor` 实例。

✨ feat(`boot/platform/src/main/java/com/plate/boot/security/core/UserAuditor.java`): 在 `UserAuditor` 类中添加了 `withCode` 方法,用于创建具有指定代码的 `UserAuditor` 实例。

✨ feat(`boot/platform/src/main/java/com/plate/boot/security/core/UserAuditor.java`): 在 `UserAuditor` 类中添加了 `withDetails` 方法,用于创建具有指定安全细节的 `UserAuditor` 实例。

✨ feat(`boot/platform/src/main/java/com/plate/boot/security/core/UserAuditor.java`): 在 `UserAuditor` 类中添加了 `withUser` 方法,用于创建具有指定用户的 `UserAuditor` 实例。
  • Loading branch information
vnobo committed Sep 18, 2024
1 parent b56fbe6 commit e86de63
Show file tree
Hide file tree
Showing 24 changed files with 784 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected <T> Flux<T> queryWithCache(Object key, String sql,
.map((row, rowMetadata) -> this.r2dbcConverter.read(entityClass, row, rowMetadata))
.all();
source = source.flatMapSequential(ContextUtils::serializeUserAuditor);
return queryWithCache(key, source);
return queryWithCache(key, source).cache();
}

/**
Expand Down Expand Up @@ -151,7 +151,7 @@ protected Mono<Long> countWithCache(Object key, String sql, Map<String, Object>
var executeSpec = this.databaseClient.sql(() -> sql);
executeSpec = executeSpec.bindValues(bindParams);
Mono<Long> source = executeSpec.mapValue(Long.class).first();
return countWithCache(key, source);
return countWithCache(key, source).cache();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.plate.boot.commons.utils.ContextUtils;
import com.plate.boot.commons.utils.query.QueryFragment;
import com.plate.boot.commons.utils.query.QueryHelper;
import org.springframework.data.domain.Persistable;
import org.springframework.data.relational.core.query.Criteria;
Expand Down Expand Up @@ -30,20 +31,18 @@ default void setCode(String code) {
}

/**
* Determines whether the entity instance is considered new.
* This is typically used to decide if the entity needs to be inserted or updated when persisted.
* The method checks if the identifier ({@code getId()}) is empty to assess newness.
* If the entity is determined to be new, it generates and assigns a new unique code ({@code setCode(ContextUtils.nextId());}).
* Determines whether the entity is new, typically indicating it has not been persisted yet.
* This is assessed by checking if the entity's identifier ({@code getId}) is empty.
* If the entity is determined to be new, a unique code is generated using {@link ContextUtils#nextId()}
* and assigned to the entity via {@link #setCode(String)}.
*
* @return {@code true} if the entity is considered new (i.e., its identifier is empty), otherwise {@code false}.
* @return {@code true} if the entity is considered new (i.e., lacks an identifier), otherwise {@code false}.
*/
@Override
@JsonIgnore
default boolean isNew() {
// 判断对象是否为新对象,通过检查ID是否为空来确定
boolean isNew = ObjectUtils.isEmpty(getId());
if (isNew) {
// 如果是新对象,则生成并设置一个新的ID
setCode(ContextUtils.nextId());
}
return isNew;
Expand All @@ -56,10 +55,25 @@ default boolean isNew() {
* @param skipKeys A {@link Collection} of {@link String} property keys to be skipped when building the criteria.
* These properties will not be included in the generated criteria.
* @return A {@link Criteria} object tailored according to the current entity,
* excluding the properties specified in the {@code skipKeys} collection.
* excluding the properties specified in the {@code skipKeys} collection.
*/
default Criteria criteria(Collection<String> skipKeys) {
// 调用CriteriaUtils的静态方法build来创建Criteria对象,并传入当前对象和要忽略的属性键集合。
return QueryHelper.criteria(this, skipKeys);
}

/**
* Constructs a QueryFragment based on the current entity's properties and conditions,
* allowing for customization of the SQL query by specifying properties to exclude.
*
* @param skipKeys A collection of String property names indicating which properties
* should not be included in the generated SQL query. This can be useful
* for skipping sensitive or unnecessary fields.
* @return A QueryFragment object containing the SQL fragment and parameters necessary
* to form a part of an SQL query. The SQL fragment represents a conditional
* part of the query (e.g., WHERE clause), and the parameters are mapped to
* prevent SQL injection, ensuring secure query execution.
*/
default QueryFragment querySql(Collection<String> skipKeys) {
return QueryHelper.query(this, skipKeys, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public static Criteria criteria(Map<String, Object> objectMap) {
}
List<Criteria> criteriaList = objectMap.entrySet().parallelStream().map(entry -> {
if (entry.getValue() instanceof String value) {
return Criteria.where(entry.getKey()).like(String.format("%s", value) + "%").ignoreCase(true);
return Criteria.where(entry.getKey()).like(String.format("%s", value)).ignoreCase(true);
} else if (entry.getValue() instanceof Collection<?> values) {
return Criteria.where(entry.getKey()).in(values);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
Expand All @@ -19,21 +18,60 @@
import reactor.core.publisher.Mono;

/**
* @author <a href="https://github.com/vnobo">Alex bob</a>
* Handles security-related endpoints for OAuth2 operations, password changes, and CSRF token retrieval.
* Utilizes WebSession-based security context repository, security manager, password encoding, and OAuth2 client repository.
*/
@RestController
@RequestMapping("/oauth2")
@RequiredArgsConstructor
public class SecurityController {

/**
* Repository responsible for managing the security context within the server's web sessions.
* It stores and retrieves the security context associated with each user's session, ensuring
* that security-related information persists across requests within the same session.
*/
private final WebSessionServerSecurityContextRepository securityContextRepository =
new WebSessionServerSecurityContextRepository();

/**
* The {@code securityManager} field is a final instance of {@link SecurityManager}, responsible for handling
* security-related operations such as user authentication, password management, and authority provisioning within
* the application. It serves as the central authority for managing user details, roles, and permissions, ensuring
* secure access control based on defined security policies.
* <p>
* This component is injected via constructor dependency injection, providing reactive services for fetching user
* details, updating passwords, registering or modifying users, loading users by OAuth2 bindings, and more, thereby
* reinforcing the security infrastructure of the {@link SecurityController}.
*/
private final SecurityManager securityManager;
/**
* Encoder used for encoding and validating passwords securely.
* This field is responsible for hashing passwords upon user registration or password updates,
* and verifying passwords during authentication processes to ensure they match the stored hash.
*/
private final PasswordEncoder passwordEncoder;
/**
* Repository responsible for storing and retrieving authorized client information for OAuth2 server-side authorization.
* This instance specifically manages the authorized clients within the server context, ensuring secure access and
* persistence of client details necessary for OAuth2 flows.
*/
private final ServerOAuth2AuthorizedClientRepository clientRepository;

@GetMapping("token")
/**
* Constructs a new instance of SecurityController.
*
* @param securityManager The SecurityManager instance responsible for security operations.
* @param passwordEncoder The PasswordEncoder used for encoding and verifying passwords.
* @param clientRepository The ServerOAuth2AuthorizedClientRepository instance for managing OAuth2 authorized clients.
*/
public SecurityController(SecurityManager securityManager, PasswordEncoder passwordEncoder,
ServerOAuth2AuthorizedClientRepository clientRepository) {
this.securityManager = securityManager;
this.passwordEncoder = passwordEncoder;
this.clientRepository = clientRepository;
}

@GetMapping("login")
public Mono<AuthenticationToken> token(ServerWebExchange exchange, Authentication authentication) {
return ReactiveSecurityContextHolder.getContext()
.delayUntil(cts -> this.securityContextRepository.save(exchange, cts))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
import java.util.Set;

/**
* SecurityDetails represents a user's security details, extending DefaultOAuth2User and implementing UserDetails.
* It encapsulates user authentication and authorization data, including OAuth2 attributes,
* tenant and group affiliations, and account status flags.
* Represents security details for a user, extending the DefaultOAuth2User and implementing UserDetails.
* This class encapsulates user identity and authentication information along with additional security-related properties.
* It is designed to work seamlessly with OAuth2-based authentication systems and Spring Security's user details interface.
*/
@Setter
@Getter
Expand Down
Loading

0 comments on commit e86de63

Please sign in to comment.