Skip to content

Commit

Permalink
增加基础数据接口 权限,更细分了.
Browse files Browse the repository at this point in the history
登录时候优化获取角色权限SQL,增加用户租户判断.
  • Loading branch information
vnobo committed Jan 12, 2024
1 parent d031c13 commit 4cb4603
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static String applyPage(Pageable pageable, String prefix) {
*/
public static String applySort(Sort sort, String prefix) {
if (sort == null || sort.isUnsorted()) {
return "";
return " order by id ";
}
sort = QueryJson.sortJson(sort, prefix);
StringJoiner sortSql = new StringJoiner(", ");
Expand Down Expand Up @@ -88,7 +88,7 @@ public static ParamSql buildParamSql(Object object, Collection<String> skipKeys,
Map<String, Object> params = jsonParamSql.params();
StringJoiner sql = jsonParamSql.sql();

if (!ObjectUtils.isEmpty(objectMap.get("securityCode"))) {
if (!skipKeys.contains("securityCode") && !ObjectUtils.isEmpty(objectMap.get("securityCode"))) {
String key = "tenant_code";
if (StringUtils.hasLength(prefix)) {
key = prefix + "." + key;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class SecurityConfiguration {
public SecurityConfiguration(Oauth2SuccessHandler authenticationSuccessHandler) {
this.authenticationSuccessHandler = authenticationSuccessHandler;
}

@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
Expand All @@ -58,9 +59,11 @@ public PasswordEncoder passwordEncoder() {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange(exchange -> {
exchange.pathMatchers("/captcha/code").permitAll();
exchange.pathMatchers("/oauth2/qr/code").permitAll();
exchange.pathMatchers("/captcha/code", "/oauth2/qr/code").permitAll();
exchange.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
exchange.pathMatchers("/tenants/**", "/users/**", "/groups/**")
.hasAnyRole("SYSTEM_ADMINISTRATORS", "ADMINISTRATORS");
exchange.pathMatchers("/menus/**", "/loggers/**").hasRole("SYSTEM_ADMINISTRATORS");
exchange.anyExchange().authenticated();
});
http.securityContextRepository(new WebSessionServerSecurityContextRepository());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,10 @@ public class Menu implements BaseEntity<Integer> {
@Id
private Integer id;

/**
* The code for this menu.
*/
private String code;

/**
* The parent code of this menu.
* The parent code can be blank if this menu is a root menu.
*/
@NotBlank(message = "Parent code cannot be blank!")
private String pcode;

/**
* The tenant code of this menu.
* The tenant code cannot be blank and identifies the tenant to which this menu belongs.
*/
@NotBlank(message = "Tenant code cannot be blank!")
private String tenantCode;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ public Mono<CsrfToken> csrfToken() {

@GetMapping("me")
public Mono<SecurityDetails> me() {
Mono<SecurityDetails> securityDetailsMono = ContextUtils.securityDetails();
return securityDetailsMono
.delayUntil(securityDetails -> this.securityManager.loginSuccess(securityDetails.getUsername()));
return ContextUtils.securityDetails();
}

@GetMapping("bind")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.time.LocalDateTime;
import java.util.HashSet;
Expand Down Expand Up @@ -52,8 +53,10 @@ public class SecurityManager extends AbstractDatabase
select * from se_authorities where user_code = :userCode
""";
private final static String QUERY_GROUP_AUTHORITY_SQL = """
select ga.*
from se_group_authorities ga join se_group_members gm on ga.group_code = gm.group_code
select ga.* from se_group_authorities ga
join se_group_members gm on ga.group_code = gm.group_code
join se_users su on gm.user_code = su.code
join se_groups sg on gm.group_code = sg.code and sg.tenant_code = su.tenant_code
where gm.user_code = :userCode
""";

Expand Down Expand Up @@ -103,18 +106,18 @@ public Mono<UserDetails> findByUsername(String username) {

return userDetailsMono.cast(UserDetails.class)
.onErrorResume(throwable -> Mono.error(new AuthenticationServiceException(
throwable.getLocalizedMessage(), throwable)));
throwable.getLocalizedMessage(), throwable)))
.publishOn(Schedulers.boundedElastic())
.doOnSuccess(securityDetails -> this.loginSuccess(securityDetails.getUsername())
.subscribe(res -> log.debug("登录成功:" + res)));
}

private Mono<SecurityDetails> buildUserDetails(User user, Set<GrantedAuthority> authorities) {
// 构建用户详细信息
SecurityDetails userDetails = SecurityDetails.of(user.getCode(), user.getUsername(), user.getName(),
user.getPassword(), user.getDisabled(), user.getAccountExpired(),
user.getAccountLocked(), user.getCredentialsExpired(), authorities, Map.of("username", user.getUsername()),
"username");
// 使用 Mono.zip 同时加载用户的组和租户信息
var tuple2Mono = Mono.zip(this.loadGroups(user.getCode()), this.loadTenants(user.getCode()));
// 将组和租户信息设置到用户详细信息中
return tuple2Mono.flatMap(tuple2 -> {
userDetails.setGroups(new HashSet<>(tuple2.getT1()));
userDetails.setTenants(new HashSet<>(tuple2.getT2()));
Expand Down Expand Up @@ -152,10 +155,10 @@ private Flux<GrantedAuthority> getGroupAuthorities(String userCode) {
.cast(GrantedAuthority.class);
}

public Mono<Void> loginSuccess(String username) {
private Mono<Long> loginSuccess(String username) {
Query query = Query.query(Criteria.where("username").is(username).ignoreCase(true));
Update update = Update.update("loginTime", LocalDateTime.now());
return this.entityTemplate.update(User.class).matching(query).apply(update).then();
return this.entityTemplate.update(User.class).matching(query).apply(update);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
Expand Down Expand Up @@ -33,6 +34,7 @@ public Mono<Page<Group>> page(GroupRequest request, Pageable pageable) {
}

@PostMapping("add")
@PreAuthorize("hasRole(@contextUtils.RULE_ADMINISTRATORS)")
public Mono<Group> add(@Valid @RequestBody GroupRequest request) {
// Check that the Group ID is null (i.e. this is a new Group)
Assert.isTrue(request.isNew(), "When adding a new Group, the ID must be null");
Expand All @@ -41,6 +43,7 @@ public Mono<Group> add(@Valid @RequestBody GroupRequest request) {
}

@PutMapping("modify")
@PreAuthorize("hasRole(@contextUtils.RULE_ADMINISTRATORS)")
public Mono<Group> modify(@Valid @RequestBody GroupRequest request) {
// Check that the Group ID is not null (i.e. this is an existing Group)
Assert.isTrue(!request.isNew(), "When modifying an existing Group, the ID must not be null");
Expand All @@ -49,6 +52,7 @@ public Mono<Group> modify(@Valid @RequestBody GroupRequest request) {
}

@DeleteMapping("delete")
@PreAuthorize("hasRole(@contextUtils.RULE_ADMINISTRATORS)")
public Mono<Void> delete(@Valid @RequestBody GroupRequest request) {
// Check that the Group ID is not null (i.e. this is an existing Group)
Assert.isTrue(!request.isNew(), "When deleting a Group, the ID must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,11 @@ public class TenantRequest extends Tenant implements Serializable {

private Map<String, Object> query;

private String securityCode;

public TenantRequest securityCode(String securityCode) {
this.setSecurityCode(securityCode);
return this;
}

public Tenant toTenant() {
return BeanUtils.copyProperties(this, Tenant.class);
}

public ParamSql bindParamSql() {
return CriteriaUtils.buildParamSql(this, List.of(), null);
return CriteriaUtils.buildParamSql(this, List.of("securityCode"), null);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.platform.boot.security.core.tenant;


import com.platform.boot.commons.utils.ContextUtils;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
Expand All @@ -22,18 +22,19 @@ public class TenantsController {
private final TenantsService tenantsService;

@GetMapping("search")
@PreAuthorize("hasRole(@contextUtils.RULE_ADMINISTRATORS)")
public Flux<Tenant> search(TenantRequest request, Pageable pageable) {
return ContextUtils.securityDetails().flatMapMany(securityDetails ->
this.tenantsService.search(request.securityCode(securityDetails.getTenantCode()), pageable));
return this.tenantsService.search(request, pageable);
}

@GetMapping("page")
@PreAuthorize("hasRole(@contextUtils.RULE_ADMINISTRATORS)")
public Mono<Page<Tenant>> page(TenantRequest request, Pageable pageable) {
return ContextUtils.securityDetails().flatMap(securityDetails ->
this.tenantsService.page(request.securityCode(securityDetails.getTenantCode()), pageable));
return this.tenantsService.page(request, pageable);
}

@PostMapping("add")
@PreAuthorize("hasRole(@contextUtils.RULE_ADMINISTRATORS)")
public Mono<Tenant> add(@Valid @RequestBody TenantRequest request) {
// Check that the Tenant ID is null (i.e. this is a new Tenant)
Assert.isTrue(request.isNew(), "When adding a new Tenant, the ID must be null");
Expand All @@ -42,6 +43,7 @@ public Mono<Tenant> add(@Valid @RequestBody TenantRequest request) {
}

@PutMapping("modify")
@PreAuthorize("hasRole(@contextUtils.RULE_ADMINISTRATORS)")
public Mono<Tenant> modify(@Valid @RequestBody TenantRequest request) {
// Check that the Tenant ID is not null (i.e. this is an existing Tenant)
Assert.isTrue(!request.isNew(), "When modifying an existing Tenant, the ID must not be null");
Expand All @@ -50,6 +52,7 @@ public Mono<Tenant> modify(@Valid @RequestBody TenantRequest request) {
}

@DeleteMapping("delete")
@PreAuthorize("hasRole(@contextUtils.RULE_ADMINISTRATORS)")
public Mono<Void> delete(@Valid @RequestBody TenantRequest request) {
// Check that the Tenant ID is not null (i.e. this is an existing Tenant)
Assert.isTrue(!request.isNew(), "When deleting a Tenant, the ID must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import lombok.Data;
import org.springframework.data.annotation.*;
import org.springframework.data.relational.core.mapping.Table;
import org.springframework.data.relational.core.query.Update;

import java.time.LocalDateTime;

Expand All @@ -22,10 +21,8 @@ public class User implements BaseEntity<Long> {
@Id
private Long id;

@NotBlank(message = "user code [code] cannot be empty!", groups = Update.class)
private String code;

@NotBlank(message = "Tenant [tenantCode] not be empty!")
private String tenantCode;

@NotBlank(message = "Login username [username] cannot be empty!")
Expand All @@ -47,10 +44,12 @@ public class User implements BaseEntity<Long> {

private Boolean credentialsExpired;

private String name;

private String email;

private String phone;

private String name;

private String avatar;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,103 @@
package com.platform.boot.security.core.user;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import com.platform.boot.security.core.UserAuditor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

import java.time.LocalDateTime;

/**
* @author <a href="https://github.com/vnobo">Alex bob</a>
*/
@Getter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class UserResponse extends User {
/**
* UserResponse.java
* <p>
* This file contains the code for the UserResponse class.
* It is written in the Java programming language.
* The code overrides the getPassword() method from the superclass
* and uses the @JsonIgnore annotation to indicate that the password
* should be ignored during serialization and deserialization.
*/

@JsonIgnore
@Override
public String getPhone() {
return super.getPhone();
}

@JsonIgnore
@Override
public String getEmail() {
return super.getEmail();
}

@JsonIgnore
@Override
public String getPassword() {
return super.getPassword();
}

@JsonIgnore
@Override
public String getUsername() {
return super.getUsername();
}

@JsonIgnore
@Override
public Boolean getDisabled() {
return super.getDisabled();
}

@JsonIgnore
@Override
public Boolean getAccountExpired() {
return super.getAccountExpired();
}

@JsonIgnore
@Override
public Boolean getAccountLocked() {
return super.getAccountLocked();
}

@JsonIgnore
@Override
public Boolean getCredentialsExpired() {
return super.getCredentialsExpired();
}

@JsonIgnore
@Override
public JsonNode getExtend() {
return super.getExtend();
}

@JsonIgnore
@Override
public LocalDateTime getLoginTime() {
return super.getLoginTime();
}

@JsonIgnore
@Override
public UserAuditor getCreator() {
return super.getCreator();
}

@JsonIgnore
@Override
public UserAuditor getUpdater() {
return super.getUpdater();
}

@JsonIgnore
@Override
public LocalDateTime getUpdatedTime() {
return super.getUpdatedTime();
}

@JsonIgnore
@Override
public LocalDateTime getCreatedTime() {
return super.getCreatedTime();
}
}
Loading

0 comments on commit 4cb4603

Please sign in to comment.