diff --git a/pom.xml b/pom.xml index fbd18d2..0e9ce0b 100644 --- a/pom.xml +++ b/pom.xml @@ -23,12 +23,10 @@ 2.5.0 5.1.3 4.4.0 + 3.5.6 - - org.springframework.boot - spring-boot-starter-data-jpa - + org.springframework.boot spring-boot-starter-web @@ -45,6 +43,16 @@ org.springframework.boot spring-boot-starter-data-redis + + + + + + + com.baomidou + mybatis-plus-spring-boot3-starter + ${mybatis-plus.version} + com.mysql @@ -75,11 +83,11 @@ ${commons-lang3.version} - - org.springdoc - springdoc-openapi-starter-webmvc-ui - ${open-api.version} - + + + + + redis.clients @@ -93,6 +101,19 @@ ${jwt.version} + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + + @@ -139,4 +160,11 @@ + + + maven_central + Maven Central + https://repo.maven.apache.org/maven2/ + + diff --git a/src/main/java/com/rainbus/dlp/DlpAdminBackendApplication.java b/src/main/java/com/rainbus/dlp/DlpAdminBackendApplication.java index 3f5ac42..c1a9aff 100644 --- a/src/main/java/com/rainbus/dlp/DlpAdminBackendApplication.java +++ b/src/main/java/com/rainbus/dlp/DlpAdminBackendApplication.java @@ -1,12 +1,12 @@ package com.rainbus.dlp; +import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -@EnableJpaAuditing @SpringBootApplication(exclude = {SecurityAutoConfiguration.class}) +@MapperScan("com.rainbus.dlp.repository.mapper") public class DlpAdminBackendApplication { public static void main(String[] args) { diff --git a/src/main/java/com/rainbus/dlp/config/JwtFilter.java b/src/main/java/com/rainbus/dlp/config/JwtFilter.java index 540670f..e816db9 100644 --- a/src/main/java/com/rainbus/dlp/config/JwtFilter.java +++ b/src/main/java/com/rainbus/dlp/config/JwtFilter.java @@ -1,6 +1,5 @@ package com.rainbus.dlp.config; -import com.rainbus.dlp.entity.dto.user.CustomUserDetails; import com.rainbus.dlp.entity.dto.user.TokenClaims; import com.rainbus.dlp.service.UserServ; import com.rainbus.dlp.util.JwtUtil; @@ -13,11 +12,9 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.lang.NonNull; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; @@ -42,10 +39,10 @@ public class JwtFilter extends OncePerRequestFilter { filterChain.doFilter(request, response); return; } + TokenClaims claims = JwtUtil.parseValidToken(token); UserDetails userDetails = userServ.loadUserByUsername(claims.getUsername()); - List authorities = claims.getRoles().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); - UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, authorities); + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); filterChain.doFilter(request, response); diff --git a/src/main/java/com/rainbus/dlp/config/MybatisMetaObjectHandler.java b/src/main/java/com/rainbus/dlp/config/MybatisMetaObjectHandler.java new file mode 100644 index 0000000..79ad839 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/config/MybatisMetaObjectHandler.java @@ -0,0 +1,47 @@ +package com.rainbus.dlp.config; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.rainbus.dlp.entity.dto.user.CustomUserDetails; +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.time.LocalDateTime; + +@Configuration +public class MybatisMetaObjectHandler implements MetaObjectHandler { + @Override + public void insertFill(MetaObject metaObject) { + if (metaObject.hasSetter("createAt")) { + this.fillStrategy(metaObject, "createAt", LocalDateTime.now()); + } + if (metaObject.hasSetter("updateAt")) { + this.fillStrategy(metaObject, "updateAt", LocalDateTime.now()); + } + if (metaObject.hasSetter("createBy")) { + this.fillStrategy(metaObject, "createBy", this.getCurrentUserId()); + } + if (metaObject.hasSetter("updateBy")) { + this.fillStrategy(metaObject, "updateBy", this.getCurrentUserId()); + } + if (metaObject.hasSetter("isDeleted")) { + this.fillStrategy(metaObject, "isDeleted", false); + } + } + + @Override + public void updateFill(MetaObject metaObject) { + if (metaObject.hasSetter("updateAt")) { + this.fillStrategy(metaObject, "updateAt", LocalDateTime.now()); + } + if (metaObject.hasSetter("updateBy")) { + this.fillStrategy(metaObject, "updateBy", this.getCurrentUserId()); + } + } + + private Long getCurrentUserId() { + CustomUserDetails userDetails = (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getDetails(); + return userDetails.getId(); + } + +} diff --git a/src/main/java/com/rainbus/dlp/config/SecurityConfig.java b/src/main/java/com/rainbus/dlp/config/SecurityConf.java similarity index 81% rename from src/main/java/com/rainbus/dlp/config/SecurityConfig.java rename to src/main/java/com/rainbus/dlp/config/SecurityConf.java index bb10c60..da70248 100644 --- a/src/main/java/com/rainbus/dlp/config/SecurityConfig.java +++ b/src/main/java/com/rainbus/dlp/config/SecurityConf.java @@ -2,36 +2,29 @@ package com.rainbus.dlp.config; import com.rainbus.dlp.entity.pojo.user.SysRole; -import com.rainbus.dlp.repository.user.SysRoleRepo; import com.rainbus.dlp.service.UserServ; -import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; -import org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.web.bind.annotation.RequestMethod; import java.util.List; @Configuration @EnableWebSecurity @RequiredArgsConstructor -public class SecurityConfig { +public class SecurityConf { private final UserServ userServ; @@ -41,7 +34,7 @@ public class SecurityConfig { .csrf(AbstractHttpConfigurer::disable) .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests((authorizeHttpRequests) -> { - userServ.getAllRoles().forEach(role -> { + userServ.listRoleResource().forEach(role -> { role.getResources().forEach(resource -> { authorizeHttpRequests.requestMatchers( HttpMethod.valueOf(resource.getRequestMethod().name()), diff --git a/src/main/java/com/rainbus/dlp/controller/ExceptionCtrl.java b/src/main/java/com/rainbus/dlp/controller/ExceptionCtrl.java new file mode 100644 index 0000000..ced2fb4 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/controller/ExceptionCtrl.java @@ -0,0 +1,16 @@ +package com.rainbus.dlp.controller; + +import com.rainbus.dlp.entity.exception.UsernameOrPasswordExcp; +import com.rainbus.dlp.entity.resp.Resp; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class ExceptionCtrl { + + @ExceptionHandler(UsernameOrPasswordExcp.class) + public Resp handler(UsernameOrPasswordExcp e) { + return Resp.fail(e.getCode(), e.getMessage()); + } + +} diff --git a/src/main/java/com/rainbus/dlp/controller/UserCtrl.java b/src/main/java/com/rainbus/dlp/controller/UserCtrl.java index 761e4ea..ddc9e98 100644 --- a/src/main/java/com/rainbus/dlp/controller/UserCtrl.java +++ b/src/main/java/com/rainbus/dlp/controller/UserCtrl.java @@ -1,60 +1,66 @@ package com.rainbus.dlp.controller; -import com.rainbus.dlp.entity.dto.user.TokenClaims; -import com.rainbus.dlp.entity.mapper.UserConv; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.rainbus.dlp.entity.converter.UserConv; import com.rainbus.dlp.entity.pojo.user.SysUser; import com.rainbus.dlp.entity.req.user.RegisterReq; import com.rainbus.dlp.entity.resp.Resp; -import com.rainbus.dlp.repository.user.SysUserRepo; -import com.rainbus.dlp.util.JwtUtil; +import com.rainbus.dlp.repository.mapper.user.SysRoleMapper; +import com.rainbus.dlp.repository.mapper.user.SysUserMapper; +import com.rainbus.dlp.service.SystemServ; +import com.rainbus.dlp.util.RedisUtil; import lombok.AllArgsConstructor; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RestController @RequestMapping("/user") @AllArgsConstructor public class UserCtrl { - private final SysUserRepo userRepo; private final UserConv userConv; private final AuthenticationManager authenticationManager; private final PasswordEncoder passwordEncoder; + private final RedisUtil redisUtil; + private final SystemServ systemServ; + private final SysUserMapper sysUserMapper; + private final SysRoleMapper sysRoleMapper; - @PostMapping("/register") - public Resp register(@RequestBody RegisterReq req) { - req.setPassword(passwordEncoder.encode(req.getPassword())); - userRepo.save(userConv.RegisterReq2Pojo(req)); + @PostMapping("/addUser") + public Resp addUser(@RequestBody @Validated RegisterReq req) { +// userRepo.save(userConv.RegisterReq2Pojo(req, defaultPwd(req.getUsername()))); return Resp.success(); } @PostMapping("/login") public Resp login(@RequestBody RegisterReq req) { - SysUser user = userRepo.findByUsername(req.getUsername()).orElse(null); - Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(req.getUsername(), req.getPassword())); - SecurityContextHolder.getContext().setAuthentication(authentication); - if (user == null) { - return Resp.fail("user not exist"); - } - if (!passwordEncoder.matches(req.getPassword(), user.getPassword())) { - return Resp.fail("password error"); - } - return Resp.success(JwtUtil.generateToken(userConv.ClaimsPojo2Dto(user))); +// SysUser user = userRepo.findByUsername(req.getUsername()).orElse(null); +// Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(req.getUsername(), req.getPassword())); +// SecurityContextHolder.getContext().setAuthentication(authentication); +// if (user == null) { +// return Resp.fail("user not exist"); +// } +// if (!passwordEncoder.matches(req.getPassword(), user.getPassword())) { +// return Resp.fail("password error"); +// } +// return Resp.success(JwtUtil.generateToken(userConv.ClaimsPojo2Dto(user))); + return Resp.success(); } - @GetMapping("token") - public Resp token() { - TokenClaims claims = new TokenClaims(); - claims.setUsername("rainbus"); - claims.setId(1L); - claims.setRoles(List.of("USER")); - return Resp.success(JwtUtil.generateToken(claims)); + @PostMapping("/test") + public Resp test() throws JsonProcessingException { + return Resp.success(redisUtil.get("user", SysUser.class)); + } + + @GetMapping("/test2") + public Resp test2() { + return Resp.success(sysRoleMapper.selectAllRoleResource()); + } + + private String defaultPwd(String username) { + return passwordEncoder.encode("Dlp" + username); } } diff --git a/src/main/java/com/rainbus/dlp/entity/mapper/UserConv.java b/src/main/java/com/rainbus/dlp/entity/converter/UserConv.java similarity index 57% rename from src/main/java/com/rainbus/dlp/entity/mapper/UserConv.java rename to src/main/java/com/rainbus/dlp/entity/converter/UserConv.java index 898f6f1..4a80e39 100644 --- a/src/main/java/com/rainbus/dlp/entity/mapper/UserConv.java +++ b/src/main/java/com/rainbus/dlp/entity/converter/UserConv.java @@ -1,5 +1,6 @@ -package com.rainbus.dlp.entity.mapper; +package com.rainbus.dlp.entity.converter; +import com.rainbus.dlp.entity.dto.user.CustomUserDetails; import com.rainbus.dlp.entity.dto.user.TokenClaims; import com.rainbus.dlp.entity.pojo.user.SysUser; import com.rainbus.dlp.entity.req.user.RegisterReq; @@ -11,9 +12,13 @@ import org.mapstruct.Mapping; public interface UserConv { @InheritInverseConfiguration - SysUser RegisterReq2Pojo(RegisterReq req); + SysUser RegisterReq2Pojo(RegisterReq req, String password); @Mapping(target = "roles", expression = "java(user.getRoles().stream().map(com.rainbus.dlp.entity.pojo.user.SysRole::getRole).toList())") TokenClaims ClaimsPojo2Dto(SysUser user); + @Mapping(target = "authorities", ignore = true) + @Mapping(target = "roles", expression = "java(user.getRoles().stream().map(com.rainbus.dlp.entity.pojo.user.SysRole::getRole).toList())") + CustomUserDetails UserPojo2UserDetails(SysUser user); + } diff --git a/src/main/java/com/rainbus/dlp/entity/dto/user/CustomUserDetails.java b/src/main/java/com/rainbus/dlp/entity/dto/user/CustomUserDetails.java index 7df90a0..b70b8b9 100644 --- a/src/main/java/com/rainbus/dlp/entity/dto/user/CustomUserDetails.java +++ b/src/main/java/com/rainbus/dlp/entity/dto/user/CustomUserDetails.java @@ -1,37 +1,56 @@ package com.rainbus.dlp.entity.dto.user; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.rainbus.dlp.entity.enums.UserStatusEnum; +import com.rainbus.dlp.entity.pojo.user.SysOrg; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; +import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; -@Getter +@Data +@NoArgsConstructor @AllArgsConstructor public class CustomUserDetails implements UserDetails { + private Long id; private String username; private String password; - private List authorities; + private List roles; @Override + @JsonIgnore + public Collection getAuthorities() { + return roles.stream().map(SimpleGrantedAuthority::new).toList(); + } + + @Override + @JsonIgnore public boolean isAccountNonExpired() { return UserDetails.super.isAccountNonExpired(); } @Override + @JsonIgnore public boolean isAccountNonLocked() { return UserDetails.super.isAccountNonLocked(); } @Override + @JsonIgnore public boolean isCredentialsNonExpired() { return UserDetails.super.isCredentialsNonExpired(); } @Override + @JsonIgnore public boolean isEnabled() { return UserDetails.super.isEnabled(); } diff --git a/src/main/java/com/rainbus/dlp/entity/enums/ExceptionEnum.java b/src/main/java/com/rainbus/dlp/entity/enums/ExceptionEnum.java new file mode 100644 index 0000000..159e2e0 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/entity/enums/ExceptionEnum.java @@ -0,0 +1,15 @@ +package com.rainbus.dlp.entity.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ExceptionEnum { + USERNAME_OR_PASSWORD_ERROR(40001, "用户名或密码错误"), + USER_DISABLED(40002, "用户当前无法使用"); + + + private final int code; + private final String message; +} diff --git a/src/main/java/com/rainbus/dlp/entity/enums/OrgTypeEnum.java b/src/main/java/com/rainbus/dlp/entity/enums/OrgTypeEnum.java new file mode 100644 index 0000000..1db836b --- /dev/null +++ b/src/main/java/com/rainbus/dlp/entity/enums/OrgTypeEnum.java @@ -0,0 +1,15 @@ +package com.rainbus.dlp.entity.enums; + +import lombok.Getter; + +@Getter +public enum OrgTypeEnum { + COMPANY("公司"), DEPARTMENT("部门"), USER_GROUP("用户组"); + + private final String desc; + + OrgTypeEnum(String desc) { + this.desc = desc; + } + +} diff --git a/src/main/java/com/rainbus/dlp/entity/enums/UserStatusEnum.java b/src/main/java/com/rainbus/dlp/entity/enums/UserStatusEnum.java new file mode 100644 index 0000000..acac67c --- /dev/null +++ b/src/main/java/com/rainbus/dlp/entity/enums/UserStatusEnum.java @@ -0,0 +1,11 @@ +package com.rainbus.dlp.entity.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum UserStatusEnum { + ACTIVATED("激活"), UNACTIVATED("未激活"), DISABLED("禁用"); + private final String desc; +} diff --git a/src/main/java/com/rainbus/dlp/entity/exception/UserDisabledExcp.java b/src/main/java/com/rainbus/dlp/entity/exception/UserDisabledExcp.java new file mode 100644 index 0000000..a756bf0 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/entity/exception/UserDisabledExcp.java @@ -0,0 +1,15 @@ +package com.rainbus.dlp.entity.exception; + +import com.rainbus.dlp.entity.enums.ExceptionEnum; +import lombok.Getter; + +@Getter +public class UserDisabledExcp extends RuntimeException { + private final int code; + private final String message; + + public UserDisabledExcp() { + this.code = ExceptionEnum.USER_DISABLED.getCode(); + this.message = ExceptionEnum.USER_DISABLED.getMessage(); + } +} diff --git a/src/main/java/com/rainbus/dlp/entity/exception/UsernameOrPasswordExcp.java b/src/main/java/com/rainbus/dlp/entity/exception/UsernameOrPasswordExcp.java new file mode 100644 index 0000000..8f4d298 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/entity/exception/UsernameOrPasswordExcp.java @@ -0,0 +1,16 @@ +package com.rainbus.dlp.entity.exception; + +import com.rainbus.dlp.entity.enums.ExceptionEnum; +import lombok.Getter; + +@Getter +public class UsernameOrPasswordExcp extends RuntimeException { + private final int code; + private final String message; + + public UsernameOrPasswordExcp() { + this.code = ExceptionEnum.USERNAME_OR_PASSWORD_ERROR.getCode(); + this.message = ExceptionEnum.USERNAME_OR_PASSWORD_ERROR.getMessage(); + } + +} diff --git a/src/main/java/com/rainbus/dlp/entity/pojo/user/SysOrg.java b/src/main/java/com/rainbus/dlp/entity/pojo/user/SysOrg.java new file mode 100644 index 0000000..f5485a5 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/entity/pojo/user/SysOrg.java @@ -0,0 +1,35 @@ +package com.rainbus.dlp.entity.pojo.user; + +import com.rainbus.dlp.entity.enums.OrgTypeEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class SysOrg { + + private Long id; + + private String org; + + private OrgTypeEnum type; + + private String fullPathName; + + private String fullPath; + + private Long parentId; + + private String region; + + private String area; + + private LocalDateTime createdAt; + + private LocalDateTime updatedAt; + + private Long createdBy; + + private Long updatedBy; + +} diff --git a/src/main/java/com/rainbus/dlp/entity/pojo/user/SysResource.java b/src/main/java/com/rainbus/dlp/entity/pojo/user/SysResource.java index fe6d9bc..e3d6df0 100644 --- a/src/main/java/com/rainbus/dlp/entity/pojo/user/SysResource.java +++ b/src/main/java/com/rainbus/dlp/entity/pojo/user/SysResource.java @@ -1,44 +1,28 @@ package com.rainbus.dlp.entity.pojo.user; -import jakarta.persistence.*; import lombok.Data; -import org.springframework.data.annotation.CreatedBy; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedBy; -import org.springframework.data.annotation.LastModifiedDate; import org.springframework.web.bind.annotation.RequestMethod; import java.time.LocalDateTime; @Data -@Entity public class SysResource { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column private String resource; - @Column - @Enumerated(EnumType.STRING) private RequestMethod requestMethod; - @Column private String description; - @CreatedBy private Long createdBy; - @LastModifiedBy private Long updatedBy; - @CreatedDate private LocalDateTime createdAt; - @LastModifiedDate private LocalDateTime updatedAt; } diff --git a/src/main/java/com/rainbus/dlp/entity/pojo/user/SysRole.java b/src/main/java/com/rainbus/dlp/entity/pojo/user/SysRole.java index 6b9a742..2073a4f 100644 --- a/src/main/java/com/rainbus/dlp/entity/pojo/user/SysRole.java +++ b/src/main/java/com/rainbus/dlp/entity/pojo/user/SysRole.java @@ -1,49 +1,26 @@ package com.rainbus.dlp.entity.pojo.user; -import com.rainbus.dlp.entity.enums.RoleEnum; -import jakarta.persistence.*; import lombok.Data; -import org.hibernate.annotations.Comment; -import org.springframework.data.annotation.CreatedBy; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedBy; -import org.springframework.data.annotation.LastModifiedDate; import java.util.List; @Data -@Entity public class SysRole { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Comment("id") private Long id; - @Comment("角色") private String role; - @Column - @Comment("描述") private String description; - @OneToMany(fetch = FetchType.EAGER) private List resources; - @CreatedBy - @Comment("创建人") private Long createdBy; - @LastModifiedBy - @Comment("更新人") private Long updatedBy; - @CreatedDate - @Comment("创建时间") private Long createdAt; - @LastModifiedDate - @Comment("更新时间") private Long updatedAt; } diff --git a/src/main/java/com/rainbus/dlp/entity/pojo/user/SysUser.java b/src/main/java/com/rainbus/dlp/entity/pojo/user/SysUser.java index 922fd7d..9d2fa36 100644 --- a/src/main/java/com/rainbus/dlp/entity/pojo/user/SysUser.java +++ b/src/main/java/com/rainbus/dlp/entity/pojo/user/SysUser.java @@ -1,50 +1,37 @@ package com.rainbus.dlp.entity.pojo.user; -import com.rainbus.dlp.entity.enums.RoleEnum; -import jakarta.persistence.*; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.rainbus.dlp.entity.enums.UserStatusEnum; import lombok.Data; -import org.springframework.data.annotation.CreatedBy; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedBy; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.time.LocalDateTime; import java.util.List; @Data -@Entity -//@SQLRestriction("is_deleted = 0") -@EntityListeners(value = AuditingEntityListener.class) -//@SQLDelete(sql = "update `user` set is_deleted = 1 where id = ?") public class SysUser { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column private String username; - @Column private String password; - @OneToMany(fetch = FetchType.EAGER) + private String email; + private List roles; - @CreatedBy + private SysOrg org; + + private UserStatusEnum status; + private Long createBy; - @LastModifiedBy private Long updateBy; - @CreatedDate private LocalDateTime createAt; - @LastModifiedDate private LocalDateTime updateAt; - @Column private Integer isDeleted; } diff --git a/src/main/java/com/rainbus/dlp/entity/req/user/RegisterReq.java b/src/main/java/com/rainbus/dlp/entity/req/user/RegisterReq.java index fee2bbb..a709a30 100644 --- a/src/main/java/com/rainbus/dlp/entity/req/user/RegisterReq.java +++ b/src/main/java/com/rainbus/dlp/entity/req/user/RegisterReq.java @@ -1,12 +1,16 @@ package com.rainbus.dlp.entity.req.user; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Pattern; import lombok.Data; @Data public class RegisterReq { + @Pattern(regexp = "^[a-zA-Z0-9_-]{4,16}$", message = "用户名格式不正确") private String username; - - private String password; + + @Email(message = "邮箱格式不正确") + private String email; } diff --git a/src/main/java/com/rainbus/dlp/entity/resp/Resp.java b/src/main/java/com/rainbus/dlp/entity/resp/Resp.java index ef98168..4e01907 100644 --- a/src/main/java/com/rainbus/dlp/entity/resp/Resp.java +++ b/src/main/java/com/rainbus/dlp/entity/resp/Resp.java @@ -20,6 +20,12 @@ public class Resp { return new Resp<>(200, "success", null); } + + + public static Resp fail(int code, String msg) { + return new Resp<>(code, msg, null); + } + public static Resp fail(String msg) { return new Resp<>(400, msg, null); } diff --git a/src/main/java/com/rainbus/dlp/repository/dao/UserDao.java b/src/main/java/com/rainbus/dlp/repository/dao/UserDao.java new file mode 100644 index 0000000..eecc48e --- /dev/null +++ b/src/main/java/com/rainbus/dlp/repository/dao/UserDao.java @@ -0,0 +1,36 @@ +package com.rainbus.dlp.repository.dao; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.rainbus.dlp.entity.pojo.user.SysRole; +import com.rainbus.dlp.entity.pojo.user.SysUser; +import com.rainbus.dlp.repository.mapper.user.SysRoleMapper; +import com.rainbus.dlp.repository.mapper.user.SysUserMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +@Component +@RequiredArgsConstructor +public class UserDao { + + private final SysUserMapper userMapper; + private final SysRoleMapper roleMapper; + + public Optional findUserByUsername(String username) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(SysUser::getUsername, username); + return Optional.ofNullable(userMapper.selectOne(wrapper)); + } + + public Optional findUserRoleOrgByUsername(String username) { + return Optional.ofNullable(userMapper.selectUserRoleOrgByUsername(username)); + } + + public List listRoleResource() { + return roleMapper.selectAllRoleResource(); + } + + +} diff --git a/src/main/java/com/rainbus/dlp/repository/mapper/user/SysOrgMapper.java b/src/main/java/com/rainbus/dlp/repository/mapper/user/SysOrgMapper.java new file mode 100644 index 0000000..79551c1 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/repository/mapper/user/SysOrgMapper.java @@ -0,0 +1,7 @@ +package com.rainbus.dlp.repository.mapper.user; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.rainbus.dlp.entity.pojo.user.SysOrg; + +public interface SysOrgMapper extends BaseMapper { +} diff --git a/src/main/java/com/rainbus/dlp/repository/mapper/user/SysResourceMapper.java b/src/main/java/com/rainbus/dlp/repository/mapper/user/SysResourceMapper.java new file mode 100644 index 0000000..b088a46 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/repository/mapper/user/SysResourceMapper.java @@ -0,0 +1,21 @@ +package com.rainbus.dlp.repository.mapper.user; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.rainbus.dlp.entity.pojo.user.SysResource; +import org.apache.ibatis.annotations.Select; +import org.mapstruct.Mapping; + +import java.util.List; + +public interface SysResourceMapper extends BaseMapper { + + @Select(""" + select * from sys_resource sr + left join sys_role_resources srr + on sr.id = srr.resources_id + where srr.sys_role_id = #{roleId} + """) + List selectListByRoleId(Long roleId); + +} diff --git a/src/main/java/com/rainbus/dlp/repository/mapper/user/SysRoleMapper.java b/src/main/java/com/rainbus/dlp/repository/mapper/user/SysRoleMapper.java new file mode 100644 index 0000000..7994ae4 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/repository/mapper/user/SysRoleMapper.java @@ -0,0 +1,35 @@ +package com.rainbus.dlp.repository.mapper.user; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.rainbus.dlp.entity.pojo.user.SysRole; +import org.apache.ibatis.annotations.*; + +import javax.management.relation.Role; +import java.util.List; + +public interface SysRoleMapper extends BaseMapper { + + @Select(""" + select * from sys_role sr + left join sys_user_roles sur + on sr.id = sur.roles_id + where sur.sys_user_id = #{userId} + """) + List selectListByUserId(Long userId); + + @Select(""" + select * from sys_role where id = 4 + """) + @Results( + @Result( + property = "resources", + column = "id", + many = @Many( + select = "com.rainbus.dlp.repository.mapper.user.SysResourceMapper.selectListByRoleId" + ) + ) + ) + List selectAllRoleResource(); + + +} diff --git a/src/main/java/com/rainbus/dlp/repository/mapper/user/SysUserMapper.java b/src/main/java/com/rainbus/dlp/repository/mapper/user/SysUserMapper.java new file mode 100644 index 0000000..a700cc9 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/repository/mapper/user/SysUserMapper.java @@ -0,0 +1,29 @@ +package com.rainbus.dlp.repository.mapper.user; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.rainbus.dlp.entity.pojo.user.SysUser; +import org.apache.ibatis.annotations.*; + +public interface SysUserMapper extends BaseMapper { + @Select(""" + select * from sys_user where username = #{username} + """) + @Results({ + @Result(column = "id", property = "id"), + @Result( + column = "id", + property = "roles", + many = @Many( + select = "com.rainbus.dlp.repository.mapper.user.SysRoleMapper.selectListByUserId" + ) + ), + @Result( + column = "org_id", + property = "org", + one = @One( + select = "com.rainbus.dlp.repository.mapper.user.SysOrgMapper.selectById" + ) + ) + }) + SysUser selectUserRoleOrgByUsername(@Param("username") String username); +} diff --git a/src/main/java/com/rainbus/dlp/repository/user/SysResourceRepo.java b/src/main/java/com/rainbus/dlp/repository/user/SysResourceRepo.java deleted file mode 100644 index 32942cf..0000000 --- a/src/main/java/com/rainbus/dlp/repository/user/SysResourceRepo.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.rainbus.dlp.repository.user; - -import com.rainbus.dlp.entity.pojo.user.SysResource; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface SysResourceRepo extends JpaRepository { -} diff --git a/src/main/java/com/rainbus/dlp/repository/user/SysRoleRepo.java b/src/main/java/com/rainbus/dlp/repository/user/SysRoleRepo.java deleted file mode 100644 index 163ebae..0000000 --- a/src/main/java/com/rainbus/dlp/repository/user/SysRoleRepo.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.rainbus.dlp.repository.user; - -import com.rainbus.dlp.entity.pojo.user.SysRole; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface SysRoleRepo extends JpaRepository { -} diff --git a/src/main/java/com/rainbus/dlp/repository/user/SysUserRepo.java b/src/main/java/com/rainbus/dlp/repository/user/SysUserRepo.java deleted file mode 100644 index 224669a..0000000 --- a/src/main/java/com/rainbus/dlp/repository/user/SysUserRepo.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.rainbus.dlp.repository.user; - -import com.rainbus.dlp.entity.pojo.user.SysUser; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.Optional; - -public interface SysUserRepo extends JpaRepository { - - Optional findByUsername(String username); - -} \ No newline at end of file diff --git a/src/main/java/com/rainbus/dlp/service/SystemServ.java b/src/main/java/com/rainbus/dlp/service/SystemServ.java new file mode 100644 index 0000000..0e257b8 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/service/SystemServ.java @@ -0,0 +1,47 @@ +package com.rainbus.dlp.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.util.pattern.PathPattern; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class SystemServ { + + private final ApplicationContext applicationContext; + + public record ApiInfo(String url, RequestMethod method) { + } + + public List getSystemApis() { + List apiInfos = new ArrayList<>(); + + RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class); + Map methodMap = mapping.getHandlerMethods(); + + for (RequestMappingInfo info : methodMap.keySet()) { + if (Objects.isNull(info.getPathPatternsCondition())) { + continue; + } + + Set patterns = info.getPathPatternsCondition().getPatterns(); + Set methods = info.getMethodsCondition().getMethods(); + for (PathPattern url : patterns) { + for (RequestMethod method : methods) { + apiInfos.add(new ApiInfo(url.getPatternString(), method)); + } + } + } + + return apiInfos; + } + +} diff --git a/src/main/java/com/rainbus/dlp/service/UserServ.java b/src/main/java/com/rainbus/dlp/service/UserServ.java index 725c065..29d17d2 100644 --- a/src/main/java/com/rainbus/dlp/service/UserServ.java +++ b/src/main/java/com/rainbus/dlp/service/UserServ.java @@ -1,44 +1,77 @@ package com.rainbus.dlp.service; +import com.rainbus.dlp.entity.converter.UserConv; import com.rainbus.dlp.entity.dto.user.CustomUserDetails; +import com.rainbus.dlp.entity.enums.UserStatusEnum; +import com.rainbus.dlp.entity.exception.UserDisabledExcp; import com.rainbus.dlp.entity.pojo.user.SysRole; import com.rainbus.dlp.entity.pojo.user.SysUser; -import com.rainbus.dlp.repository.user.SysResourceRepo; -import com.rainbus.dlp.repository.user.SysRoleRepo; -import com.rainbus.dlp.repository.user.SysUserRepo; +import com.rainbus.dlp.repository.dao.UserDao; +import com.rainbus.dlp.util.RedisUtil; import lombok.AllArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import org.springframework.validation.SimpleErrors; +import javax.management.relation.Role; import java.util.List; -import java.util.stream.Collectors; +import java.util.Optional; @Service @AllArgsConstructor public class UserServ implements UserDetailsService { - private final SysUserRepo userRepo; - private final SysRoleRepo roleRepo; - private final SysResourceRepo resourceRepo; + private final UserConv userConv; + private final UserDao userDao; + + public static final String REDIS_USER_DETAILS = "user_details_%s"; + public static final long REDIS_USER_DETAILS_EXPIRE = 1 * 60 * 60; + private final RedisUtil redisUtil; public SysUser getUserByUsername(String username) { - return userRepo.findByUsername(username).orElse(null); + Optional user = userDao.findUserByUsername(username); + if (user.isEmpty()) { + throw new UsernameNotFoundException("用户不存在"); + } + return user.get(); } - public List getAllRoles() { - return roleRepo.findAll(); + public List listRoleResource() { + return userDao.listRoleResource(); } +// public List getAllRoles() { +// return roleRepo.findAll(); +// } + @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - SysUser user = userRepo.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("user not exist")); - List authorities = user.getRoles().stream().map(role -> new SimpleGrantedAuthority(role.getRole())).toList(); - return new CustomUserDetails(user.getUsername(), user.getPassword(), authorities); + // 读缓存 + Optional userDetailsOpt = loadUserDetailsFromRedis(username); + if (userDetailsOpt.isPresent()) { + return userDetailsOpt.get(); + } + + // 读数据库 + Optional user = userDao.findUserRoleOrgByUsername(username); + if (user.isEmpty()) { + throw new UsernameNotFoundException("用户不存在"); + } + if (user.get().getStatus() == UserStatusEnum.DISABLED) { + throw new UserDisabledExcp(); + } + CustomUserDetails userDetails = userConv.UserPojo2UserDetails(user.get()); + + // 写缓存 + redisUtil.setex(RedisUtil.parseKey(REDIS_USER_DETAILS, username), userDetails, REDIS_USER_DETAILS_EXPIRE); + + return userDetails; } + + private Optional loadUserDetailsFromRedis(String username) { + return redisUtil.get(RedisUtil.parseKey(REDIS_USER_DETAILS, username), CustomUserDetails.class); + } + } diff --git a/src/main/java/com/rainbus/dlp/util/ConvertUtil.java b/src/main/java/com/rainbus/dlp/util/ConvertUtil.java index 8be6ef5..725a260 100644 --- a/src/main/java/com/rainbus/dlp/util/ConvertUtil.java +++ b/src/main/java/com/rainbus/dlp/util/ConvertUtil.java @@ -1,5 +1,6 @@ package com.rainbus.dlp.util; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.MapType; @@ -8,7 +9,7 @@ import java.util.Map; public class ConvertUtil { - private static final ObjectMapper mapper = new ObjectMapper(); + private static final ObjectMapper mapper = new ObjectMapper().findAndRegisterModules(); public static Map toMap(T source, Class vClass) { MapType mapType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, vClass); @@ -19,4 +20,11 @@ public class ConvertUtil { return mapper.convertValue(map, tClass); } + public static T fromJsonStr(String jsonStr, Class tClass) throws JsonProcessingException { + return mapper.readValue(jsonStr, tClass); + } + + public static String toJsonStr(V value) throws JsonProcessingException { + return mapper.writeValueAsString(value); + } } diff --git a/src/main/java/com/rainbus/dlp/util/RedisUtil.java b/src/main/java/com/rainbus/dlp/util/RedisUtil.java new file mode 100644 index 0000000..12cb387 --- /dev/null +++ b/src/main/java/com/rainbus/dlp/util/RedisUtil.java @@ -0,0 +1,67 @@ +package com.rainbus.dlp.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.AllArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.Optional; + +@Component +@AllArgsConstructor +public class RedisUtil { + + private final RedisTemplate redisTemplate; + + public boolean set(String key, String value) { + redisTemplate.opsForValue().set(key, value); + return true; + } + + public boolean set(String key, V value) { + try { + set(key, ConvertUtil.toJsonStr(value)); + } catch (JsonProcessingException e) { + return false; + } + return true; + } + + public Optional get(String key) { + return Optional.ofNullable(redisTemplate.opsForValue().get(key)); + } + + public Optional get(String key, Class vClass) { + return get(key).map(s -> { + try { + return ConvertUtil.fromJsonStr(s, vClass); + } catch (JsonProcessingException e) { + return null; + } + }); + } + + public void delete(String key) { + redisTemplate.delete(key); + } + + public boolean setex(String key, String value, long timeout) { + redisTemplate.opsForValue().set(key, value, Duration.ofSeconds(timeout)); + return true; + } + + public boolean setex(String key, V value, long timeout) { + try { + setex(key, ConvertUtil.toJsonStr(value), timeout); + } catch (JsonProcessingException e) { + return false; + } + return true; + } + + public static String parseKey(String pattern, Object... args) { + return String.format(pattern, args); + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 19888cb..09c9c44 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -7,10 +7,7 @@ spring: username: root password: 13291004986@lm driver-class-name: com.mysql.cj.jdbc.Driver - jpa: - hibernate: - ddl-auto: update - show-sql: true + data: redis: @@ -19,3 +16,10 @@ spring: password: 13291004986 timeout: 10000 database: 0 +logging: + level: + com: + rainbus: + dlp: + repository: + mapper: debug