diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/config/SecurityConfig.java b/Pinnacle/src/main/java/com/cfive/pinnacle/config/SecurityConfig.java index 1f323d0..40920e2 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/config/SecurityConfig.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/config/SecurityConfig.java @@ -14,6 +14,11 @@ 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.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.List; @Configuration public class SecurityConfig { @@ -42,7 +47,7 @@ public class SecurityConfig { } @Bean - AuthenticationManager authenticationManager(HttpSecurity httpSecurity, PasswordEncoder passwordEncoder) throws Exception { + public AuthenticationManager authenticationManager(HttpSecurity httpSecurity, PasswordEncoder passwordEncoder) throws Exception { return httpSecurity.getSharedObject(AuthenticationManagerBuilder.class) .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder) @@ -50,22 +55,38 @@ public class SecurityConfig { .build(); } + @Bean + public CorsConfigurationSource corsConfigurationSource(){ + CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.setAllowedMethods(List.of("*")); + corsConfiguration.setAllowedHeaders(List.of("*")); + corsConfiguration.setMaxAge(3600L); + corsConfiguration.setAllowedOrigins(List.of("*")); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**",corsConfiguration); + return source; + } + @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { return httpSecurity // Disable CSRF - .csrf().disable() + .csrf() + .disable() // Do not get SecurityContent by Session - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() // Allow anonymous access .authorizeHttpRequests() - .requestMatchers("/login").anonymous() + .requestMatchers("/login") + .anonymous() // Authentication required - .anyRequest().authenticated() + .anyRequest() + .authenticated() .and() .logout() @@ -75,6 +96,10 @@ public class SecurityConfig { .authenticationEntryPoint(authenticationEntryPointHandler) .and() + .cors() + .configurationSource(corsConfigurationSource()) + .and() + .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class) .build(); } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/ElementController.java b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/ElementController.java index f4e8cdd..cbe8fce 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/ElementController.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/ElementController.java @@ -1,8 +1,17 @@ package com.cfive.pinnacle.controller.permission; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.cfive.pinnacle.entity.common.ResponseResult; +import com.cfive.pinnacle.entity.permission.Element; +import com.cfive.pinnacle.service.permission.IElementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** *

* 页面元素 前端控制器 @@ -14,5 +23,26 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/element") public class ElementController { + private IElementService elementService; + @Autowired + public void setElementService(IElementService elementService) { + this.elementService = elementService; + } + + @GetMapping + public ResponseResult getAllElement() { + List elements = elementService.list(); + + return ResponseResult.databaseSelectSuccess(elements); + } + + @GetMapping("/{id}") + public ResponseResult getElement(@PathVariable long id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Element::getId, id); + Element element = elementService.getOne(wrapper); + + return ResponseResult.databaseSelectSuccess(element); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/FileController.java b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/FileController.java index de8ced5..2ffb710 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/FileController.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/FileController.java @@ -1,8 +1,17 @@ package com.cfive.pinnacle.controller.permission; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.cfive.pinnacle.entity.common.ResponseResult; +import com.cfive.pinnacle.entity.permission.File; +import com.cfive.pinnacle.service.permission.IFileService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** *

* 文件 前端控制器 @@ -14,5 +23,26 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/file") public class FileController { + private IFileService fileService; + @Autowired + public void setFileService(IFileService fileService) { + this.fileService = fileService; + } + + @GetMapping + public ResponseResult getAllFile() { + List files = fileService.list(); + + return ResponseResult.databaseSelectSuccess(files); + } + + @GetMapping("/{id}") + public ResponseResult getFile(@PathVariable int id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(File::getId, id); + File file = fileService.getOne(wrapper); + + return ResponseResult.databaseSelectSuccess(file); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/LoginController.java b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/LoginController.java index 3c0d9a1..b726461 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/LoginController.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/LoginController.java @@ -5,14 +5,14 @@ import com.cfive.pinnacle.entity.common.ResponseCode; import com.cfive.pinnacle.entity.common.ResponseResult; import com.cfive.pinnacle.service.permission.ILoginService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; import java.util.HashMap; @RestController +@CrossOrigin public class LoginController { private ILoginService loginService; @@ -37,4 +37,11 @@ public class LoginController { return ResponseResult.build(ResponseCode.LOGOUT_FAILED, "Logout Failed", null); } } + + @GetMapping("/userInfo") + public ResponseResult getUserInfo() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Object principal = authentication.getPrincipal(); + return ResponseResult.success(principal); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/MenuController.java b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/MenuController.java index 6b57a22..3583d35 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/MenuController.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/MenuController.java @@ -1,8 +1,17 @@ package com.cfive.pinnacle.controller.permission; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.cfive.pinnacle.entity.common.ResponseResult; +import com.cfive.pinnacle.entity.permission.Menu; +import com.cfive.pinnacle.service.permission.IMenuService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** *

* 菜单 前端控制器 @@ -14,5 +23,26 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/menu") public class MenuController { + private IMenuService menuService; + @Autowired + public void setMenuService(IMenuService menuService) { + this.menuService = menuService; + } + + @GetMapping + public ResponseResult getAllMenu() { + List

menus = menuService.list(); + + return ResponseResult.databaseSelectSuccess(menus); + } + + @GetMapping("/{id}") + public ResponseResult getMenu(@PathVariable int id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Menu::getId, id); + Menu menu = menuService.getOne(wrapper); + + return ResponseResult.databaseSelectSuccess(menu); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/OperationController.java b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/OperationController.java index cd89761..f262245 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/OperationController.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/OperationController.java @@ -1,8 +1,17 @@ package com.cfive.pinnacle.controller.permission; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.cfive.pinnacle.entity.common.ResponseResult; +import com.cfive.pinnacle.entity.permission.Operation; +import com.cfive.pinnacle.service.permission.IOperationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** *

* 功能 前端控制器 @@ -14,5 +23,26 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/operation") public class OperationController { + private IOperationService operationService; + @Autowired + public void setOperationService(IOperationService operationService) { + this.operationService = operationService; + } + + @GetMapping + public ResponseResult getAllOperation() { + List operations = operationService.list(); + + return ResponseResult.databaseSelectSuccess(operations); + } + + @GetMapping("/{id}") + public ResponseResult getOperation(@PathVariable int id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Operation::getId, id); + Operation operation = operationService.getOne(wrapper); + + return ResponseResult.databaseSelectSuccess(operation); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/OperationLogController.java b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/OperationLogController.java index d1a71d3..f7031ad 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/OperationLogController.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/OperationLogController.java @@ -1,8 +1,17 @@ package com.cfive.pinnacle.controller.permission; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.cfive.pinnacle.entity.common.ResponseResult; +import com.cfive.pinnacle.entity.permission.OperationLog; +import com.cfive.pinnacle.service.permission.IOperationLogService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** *

* 操作日志 前端控制器 @@ -14,5 +23,26 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/operationLog") public class OperationLogController { + private IOperationLogService operationLogService; + @Autowired + public void setOperationLogService(IOperationLogService operationLogService) { + this.operationLogService = operationLogService; + } + + @GetMapping + public ResponseResult getAllOperationLog() { + List operationLogs = operationLogService.list(); + + return ResponseResult.databaseSelectSuccess(operationLogs); + } + + @GetMapping("/{id}") + public ResponseResult getOperationLog(@PathVariable int id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(OperationLog::getId, id); + OperationLog operationLog = operationLogService.getOne(wrapper); + + return ResponseResult.databaseSelectSuccess(operationLog); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/PowerController.java b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/PowerController.java index 5101278..1dc88c9 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/PowerController.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/PowerController.java @@ -1,5 +1,10 @@ package com.cfive.pinnacle.controller.permission; +import com.cfive.pinnacle.entity.common.ResponseResult; +import com.cfive.pinnacle.entity.permission.PowerSet; +import com.cfive.pinnacle.service.permission.IPowerService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -14,5 +19,17 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/power") public class PowerController { + private IPowerService powerService; + @Autowired + public void setPowerService(IPowerService powerService) { + this.powerService = powerService; + } + + @GetMapping + public ResponseResult getAllPower() { + PowerSet powerSet = powerService.getAllPower(); + + return ResponseResult.databaseSelectSuccess(powerSet); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/PowerTypeController.java b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/PowerTypeController.java index 2ad9fe1..507293a 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/PowerTypeController.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/controller/permission/PowerTypeController.java @@ -1,11 +1,11 @@ package com.cfive.pinnacle.controller.permission; -import com.cfive.pinnacle.entity.common.ResponseCode; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.cfive.pinnacle.entity.common.ResponseResult; import com.cfive.pinnacle.entity.permission.*; import com.cfive.pinnacle.service.permission.*; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -22,16 +22,25 @@ import java.util.List; @RestController @RequestMapping("/powerType") public class PowerTypeController { - IPowerService powerTypeService; + IPowerTypeService powerTypeService; - @Autowired - public void setPowerTypeService(IPowerService powerTypeService) { + public void setPowerTypeService(IPowerTypeService powerTypeService) { this.powerTypeService = powerTypeService; } @GetMapping public ResponseResult getAllPowerType() { - List powerTypes = powerTypeService.list(); - return ResponseResult.build(ResponseCode.DATABASE_SELECT_OK, "success", powerTypes); + List powerTypes = powerTypeService.list(); + + return ResponseResult.databaseSelectSuccess(powerTypes); + } + + @GetMapping("/{id}") + public ResponseResult getPowerType(@PathVariable int id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(PowerType::getId, id); + PowerType powerType = powerTypeService.getOne(wrapper); + + return ResponseResult.databaseSelectSuccess(powerType); } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/entity/common/ResponseResult.java b/Pinnacle/src/main/java/com/cfive/pinnacle/entity/common/ResponseResult.java index 7f8dd72..53587ca 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/entity/common/ResponseResult.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/entity/common/ResponseResult.java @@ -55,4 +55,20 @@ public class ResponseResult implements Serializable { public static ResponseResult fail(String msg, Object data) { return build(ResponseCode.SYSTEM_ERROR, msg, data); } + + public static ResponseResult databaseSelectSuccess(Object object) { + return build(ResponseCode.DATABASE_SELECT_OK, "success", object); + } + + public static ResponseResult databaseSaveSuccess(Object object) { + return build(ResponseCode.DATABASE_SAVE_OK, "success", object); + } + + public static ResponseResult databaseUpdateSuccess(Object object) { + return build(ResponseCode.DATABASE_UPDATE_OK, "success", object); + } + + public static ResponseResult databaseDeleteSuccess() { + return build(ResponseCode.DATABASE_DELETE_OK, "success", null); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/LoginUser.java b/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/LoginUser.java index 338f644..faa9d28 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/LoginUser.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/LoginUser.java @@ -1,6 +1,7 @@ package com.cfive.pinnacle.entity.permission; import com.cfive.pinnacle.entity.User; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -14,102 +15,46 @@ import java.util.Collection; @AllArgsConstructor public class LoginUser implements UserDetails { private User user; - private Collection authorities; - private String password; - private String username; - private Boolean accountNonExpired = true; - private Boolean accountNonLocked = true; - private Boolean credentialsNonExpired = true; - private Boolean enabled = true; - - public LoginUser(User user) { - this.user = user; - this.username = user.getUsername(); - this.password = user.getPasswd(); - this.enabled = user.getEnable() == 1; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } + @JsonIgnore + @Override public Collection getAuthorities() { - return authorities; - } - - public void setAuthorities(Collection authorities) { - this.authorities = authorities; + return null; } + @JsonIgnore + @Override public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; + return user.getPasswd(); } + @JsonIgnore + @Override public String getUsername() { - return username; + return user.getUsername(); } + @JsonIgnore @Override public boolean isAccountNonExpired() { - return this.accountNonExpired; + return true; } + @JsonIgnore @Override public boolean isAccountNonLocked() { - return this.accountNonLocked; + return true; } + @JsonIgnore @Override public boolean isCredentialsNonExpired() { - return this.credentialsNonExpired; + return true; } + @JsonIgnore @Override public boolean isEnabled() { - return this.enabled; - } - - public void setUsername(String username) { - this.username = username; - } - - public Boolean getAccountNonExpired() { - return accountNonExpired; - } - - public void setAccountNonExpired(Boolean accountNonExpired) { - this.accountNonExpired = accountNonExpired; - } - - public Boolean getAccountNonLocked() { - return accountNonLocked; - } - - public void setAccountNonLocked(Boolean accountNonLocked) { - this.accountNonLocked = accountNonLocked; - } - - public Boolean getCredentialsNonExpired() { - return credentialsNonExpired; - } - - public void setCredentialsNonExpired(Boolean credentialsNonExpired) { - this.credentialsNonExpired = credentialsNonExpired; - } - - public Boolean getEnabled() { - return enabled; - } - - public void setEnabled(Boolean enabled) { - this.enabled = enabled; + return user.getEnable() == 1; } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/Operation.java b/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/Operation.java index 430e992..76c067d 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/Operation.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/Operation.java @@ -45,12 +45,6 @@ public class Operation implements Serializable { @TableField("code") private String code; - /** - * URL 前缀 - */ - @TableField("url_prefix") - private String urlPrefix; - /** * 权限ID */ diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/PowerSet.java b/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/PowerSet.java new file mode 100644 index 0000000..6c0882d --- /dev/null +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/entity/permission/PowerSet.java @@ -0,0 +1,28 @@ +package com.cfive.pinnacle.entity.permission; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class PowerSet implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private List operationList; + + private List

menuList; + + private List elementList; + + private List fileList; +} diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/filter/JwtAuthenticationTokenFilter.java b/Pinnacle/src/main/java/com/cfive/pinnacle/filter/JwtAuthenticationTokenFilter.java index 25d46c6..a083aec 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/filter/JwtAuthenticationTokenFilter.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/filter/JwtAuthenticationTokenFilter.java @@ -49,7 +49,7 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { if (Objects.isNull(loginUser)) { throw new RuntimeException("Not logged in"); } - + // Todo 权限 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, null); SecurityContextHolder.getContext().setAuthentication(authenticationToken); diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/IPowerService.java b/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/IPowerService.java index 63dfc7d..d9c6bf3 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/IPowerService.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/IPowerService.java @@ -2,6 +2,7 @@ package com.cfive.pinnacle.service.permission; import com.cfive.pinnacle.entity.permission.Power; import com.baomidou.mybatisplus.extension.service.IService; +import com.cfive.pinnacle.entity.permission.PowerSet; /** *

@@ -12,5 +13,5 @@ import com.baomidou.mybatisplus.extension.service.IService; * @since 2023-04-30 */ public interface IPowerService extends IService { - + PowerSet getAllPower(); } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/LoginServiceImpl.java b/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/LoginServiceImpl.java index 859045c..2c8c1ea 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/LoginServiceImpl.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/LoginServiceImpl.java @@ -39,6 +39,7 @@ public class LoginServiceImpl implements ILoginService { } LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + loginUser.getUser().setPasswd(""); String userId = loginUser.getUser().getId().toString(); String jwt = JwtUtil.createJWT(userId); diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/PowerServiceImpl.java b/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/PowerServiceImpl.java index b9e80a0..cb113ea 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/PowerServiceImpl.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/PowerServiceImpl.java @@ -1,11 +1,14 @@ package com.cfive.pinnacle.service.permission.impl; -import com.cfive.pinnacle.entity.permission.Power; +import com.cfive.pinnacle.entity.permission.*; import com.cfive.pinnacle.mapper.permission.PowerMapper; -import com.cfive.pinnacle.service.permission.IPowerService; +import com.cfive.pinnacle.service.permission.*; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.List; + /** *

* 权限 服务实现类 @@ -16,5 +19,38 @@ import org.springframework.stereotype.Service; */ @Service public class PowerServiceImpl extends ServiceImpl implements IPowerService { + private IOperationService operationService; + private IMenuService menuService; + private IElementService elementService; + private IFileService fileService; + @Autowired + public void setOperationService(IOperationService operationService) { + this.operationService = operationService; + } + + @Autowired + public void setMenuService(IMenuService menuService) { + this.menuService = menuService; + } + + @Autowired + public void setElementService(IElementService elementService) { + this.elementService = elementService; + } + + @Autowired + public void setFileService(IFileService fileService) { + this.fileService = fileService; + } + + @Override + public PowerSet getAllPower() { + List operationList = operationService.list(); + List

menuList = menuService.list(); + List elementList = elementService.list(); + List fileList = fileService.list(); + + return new PowerSet(operationList, menuList, elementList, fileList); + } } diff --git a/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/UserDetailsServiceImpl.java b/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/UserDetailsServiceImpl.java index b3df354..8cef370 100644 --- a/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/UserDetailsServiceImpl.java +++ b/Pinnacle/src/main/java/com/cfive/pinnacle/service/permission/impl/UserDetailsServiceImpl.java @@ -29,6 +29,9 @@ public class UserDetailsServiceImpl implements UserDetailsService { if (Objects.isNull(user)) { throw new UsernameNotFoundException("Username not found in database"); } + + // Todo 权限 + return new LoginUser(user); } } diff --git a/Pinnacle/src/test/java/com/cfive/pinnacle/service/IUserServiceTest.java b/Pinnacle/src/test/java/com/cfive/pinnacle/service/IUserServiceTest.java index a78e578..9e048fc 100644 --- a/Pinnacle/src/test/java/com/cfive/pinnacle/service/IUserServiceTest.java +++ b/Pinnacle/src/test/java/com/cfive/pinnacle/service/IUserServiceTest.java @@ -1,5 +1,6 @@ package com.cfive.pinnacle.service; +import com.cfive.pinnacle.entity.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -18,4 +19,19 @@ class IUserServiceTest { void getBCy(@Autowired PasswordEncoder passwordEncoder) { System.out.println(passwordEncoder.encode("123")); } + + @Test + void addUser(@Autowired IUserService userService, @Autowired PasswordEncoder passwordEncoder) { + User user = new User(); + user.setUsername("ggb"); + user.setPasswd(passwordEncoder.encode("123")); + user.setDepartmentId(1652713919467151362L); + user.setEnable(1); + userService.save(user); + } + + @Test + void removeUser(@Autowired IUserService userService) { + userService.removeById(1); + } } \ No newline at end of file diff --git a/sql/Insert.sql b/sql/Insert.sql new file mode 100644 index 0000000..7753840 --- /dev/null +++ b/sql/Insert.sql @@ -0,0 +1,60 @@ +SET FOREIGN_KEY_CHECKS=0; + +truncate t_menu; +truncate t_element; +truncate t_file; +truncate t_operation_log; +truncate t_operation; +truncate t_power; +truncate t_power_type; + +insert into t_power_type (id, name) +values (1, 'operation'), + (2, 'menu'), + (3, 'element'), + (4, 'file'); + +begin; +insert into t_power (type_id) +values (1); +insert into t_operation (name, code, power_id, parent_id) +values ('Select All Power Type', 'system:power_type:all', last_insert_id(), null); +commit; + + +begin; +insert into t_power (type_id) +values (1); +insert into t_operation (name, code, power_id, parent_id) +values ('Select All Power', 'system:power:all', last_insert_id(), null); +commit; + +begin; +insert into t_power (type_id) +values (1); +insert into t_operation (name, code, power_id, parent_id) +values ('Select All User', 'system:operation:all', last_insert_id(), null); +commit; + +begin; +insert into t_power (type_id) +values (1); +insert into t_operation (name, code, power_id, parent_id) +values ('Select All User', 'system:menu:all', last_insert_id(), null); +commit; + +begin; +insert into t_power (type_id) +values (1); +insert into t_operation (name, code, power_id, parent_id) +values ('Select All User', 'system:element:all', last_insert_id(), null); +commit; + +begin; +insert into t_power (type_id) +values (1); +insert into t_operation (name, code, power_id, parent_id) +values ('Select All User', 'system:file:all', last_insert_id(), null); +commit; + +SET FOREIGN_KEY_CHECKS=1; \ No newline at end of file diff --git a/sql/init.sql b/sql/init.sql index c36556f..6bcfaa7 100644 --- a/sql/init.sql +++ b/sql/init.sql @@ -69,7 +69,6 @@ create table `t_operation` `id` bigint not null primary key auto_increment, `name` varchar(50) not null comment '功能名', `code` varchar(50) null comment '功能编码', - `url_prefix` varchar(100) null comment 'URL 前缀', `power_id` bigint not null comment '权限ID', `parent_id` bigint null comment '父ID', constraint t_operation_power_id_fk foreign key (power_id) references t_power (id) @@ -298,32 +297,4 @@ create table `t_attendance` `version` int not null default 0, constraint t_attendance_user_id_fk foreign key (user_id) references t_user (id), constraint t_attendance_modify_id_fk foreign key (modify_id) references t_user (id) -) comment '考勤'; - -insert into t_power_type (id, name) -values (1, 'operation'), - (2, 'menu'), - (3, 'element'), - (4, 'file'); - -begin; -insert into t_power (type_id) -values (1); -insert into t_operation (name, code, url_prefix, power_id, parent_id) -values ('Select All Power Type', 'select_all_power_type', 'GET:/powerType', last_insert_id(), null); -commit; - - -begin; -insert into t_power (type_id) -values (1); -insert into t_operation (name, code, url_prefix, power_id, parent_id) -values ('Select All Power Type', 'select_all_power_type', 'GET:/powerType', last_insert_id(), null); -commit; - -begin; -insert into t_power (type_id) -values (1); -insert into t_operation (name, code, url_prefix, power_id, parent_id) -values ('Select All User', 'select_all_user', 'GET:/user', last_insert_id(), null); -commit; \ No newline at end of file +) comment '考勤'; \ No newline at end of file diff --git a/ui/.eslintrc.cjs b/ui/.eslintrc.cjs index 6bc57c7..2445c43 100644 --- a/ui/.eslintrc.cjs +++ b/ui/.eslintrc.cjs @@ -22,7 +22,7 @@ module.exports = { rules: { "no-cond-assign": "error", "eqeqeq": "error", - "indent": ["error", 4], + "indent": ["error", 4, {"SwitchCase": 1}], "prettier/prettier": [ "error", { diff --git a/ui/src/assets/svg/back-shape.svg b/ui/src/assets/svg/back-shape.svg new file mode 100644 index 0000000..43f0513 --- /dev/null +++ b/ui/src/assets/svg/back-shape.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/ui/src/assets/svg/password.svg b/ui/src/assets/svg/password.svg new file mode 100644 index 0000000..2f80d53 --- /dev/null +++ b/ui/src/assets/svg/password.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/ui/src/constants/Common.constants.ts b/ui/src/constants/Common.constants.ts index da50c57..4f949c1 100644 --- a/ui/src/constants/Common.constants.ts +++ b/ui/src/constants/Common.constants.ts @@ -1,4 +1,5 @@ const PRODUCTION_NAME = 'Pinnacle OA' +const TOKEN_NAME = 'JWT_TOKEN' const COLOR_PRODUCTION = '#00D4FF' const COLOR_BACKGROUND = '#D8D8D8' const COLOR_FONT_MAIN = '#4D4D4D' @@ -11,6 +12,7 @@ const SIZE_ICON_XL = '64px' export { PRODUCTION_NAME, + TOKEN_NAME, COLOR_PRODUCTION, COLOR_BACKGROUND, COLOR_FONT_MAIN, diff --git a/ui/src/main.ts b/ui/src/main.ts index 08649c1..c09550d 100644 --- a/ui/src/main.ts +++ b/ui/src/main.ts @@ -5,18 +5,6 @@ import router from '@/router' import '@/assets/css/base.css' import '@/assets/css/common.css' -/* -router.beforeEach((to, from, next) => { - if (to.matched.length === 0) { - from.path ? next({ path: from.path }) : next('/') - } else { - if (to.meta.title) { - document.title = PRODUCTION_NAME + ' - ' + to.meta.title - } - } -}) -*/ - const app = createApp(App) app.use(router).mount('#app') diff --git a/ui/src/pages/Login.vue b/ui/src/pages/Login.vue new file mode 100644 index 0000000..b6a6e8a --- /dev/null +++ b/ui/src/pages/Login.vue @@ -0,0 +1,273 @@ + + + + + diff --git a/ui/src/pages/Main.vue b/ui/src/pages/Main.vue index e181a2d..54d4a0d 100644 --- a/ui/src/pages/Main.vue +++ b/ui/src/pages/Main.vue @@ -106,7 +106,7 @@ @@ -155,9 +155,17 @@ import { SIZE_ICON_SM } from '@/constants/Common.constants.js' import _ from 'lodash' +import { getUsername, logout } from '@/utils/auth' export default { name: 'MainFrame', + data() { + return { + routes: _.filter(_.get(this.$router, 'options.routes[0].children'), 'meta.title'), + isCollapsed: false, + username: '' + } + }, methods: { SIZE_ICON_LG() { return SIZE_ICON_LG @@ -176,16 +184,16 @@ export default { }, COLOR_FONT_MAIN() { return COLOR_FONT_MAIN - } - }, - data() { - return { - routes: _.filter(_.get(this.$router, 'options.routes[0].children'), 'meta.title'), - isCollapsed: false + }, + logout() { + logout() + this.$router.push({ name: 'Login' }) } }, mounted() { - console.log(this.routes) + getUsername().then((res) => { + this.username = res.toString() + }) } } diff --git a/ui/src/router/index.ts b/ui/src/router/index.ts index 88bc690..a82e12d 100644 --- a/ui/src/router/index.ts +++ b/ui/src/router/index.ts @@ -1,4 +1,6 @@ import { createRouter, createWebHistory } from 'vue-router' +import { PRODUCTION_NAME } from '@/constants/Common.constants' +import { getLoginStatus } from '@/utils/auth' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -23,8 +25,41 @@ const router = createRouter({ } } ] + }, + { + path: '/login', + component: async () => await import('@/pages/Login.vue'), + name: 'Login', + meta: { + title: '登录' + } } ] }) +router.beforeEach((to, from, next) => { + if (to.matched.length === 0) { + from.path !== '' ? next({ path: from.path }) : next('/') + } else { + if (to.meta.title !== '') { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + document.title = `${PRODUCTION_NAME} - ${to.meta.title}` + } + + if (getLoginStatus()) { + if (to.name === 'Login') { + next('/') + } else { + next() + } + } else { + if (to.name === 'Login') { + next() + } else { + next('/login') + } + } + } +}) + export default router diff --git a/ui/src/services/index.ts b/ui/src/services/index.ts index e69de29..8813f04 100644 --- a/ui/src/services/index.ts +++ b/ui/src/services/index.ts @@ -0,0 +1,68 @@ +import axios, { type AxiosError } from 'axios' +import { getToken, removeToken } from '@/utils/common' +import router from '@/router' + +const service = axios.create({ + baseURL: 'http://localhost:8621', + timeout: 10000, + withCredentials: false +}) + +service.interceptors.request.use( + (config) => { + const token = getToken() + if (token != null) { + config.headers.set('token', token) + } + return config + }, + async (error) => { + return await Promise.reject(error) + } +) + +service.interceptors.response.use( + (response) => { + return response + }, + async (error) => { + if (error.response != null) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + console.log(`request error: ${error.response.code} - ${error.response.msg}`) + switch (error.response.code) { + case 30010: + removeToken() + await router.push({ name: 'Login' }) + } + } + return await Promise.reject(error?.response?.data) + } +) + +const request = { + async get(url: string, data?: any): Promise { + return await request.request('GET', url, { params: data }) + }, + async post(url: string, data?: any): Promise { + return await request.request('POST', url, { data }) + }, + async put(url: string, data?: any): Promise { + return await request.request('PUT', url, { data }) + }, + async delete(url: string, data?: any): Promise { + return await request.request('DELETE', url, { params: data }) + }, + async request(method = 'GET', url: string, data?: any): Promise { + return await new Promise((resolve, reject) => { + service({ method, url, ...data }) + .then((res) => { + resolve(res as unknown as Promise) + }) + .catch((e: Error | AxiosError) => { + reject(e) + }) + }) + } +} + +export default request diff --git a/ui/src/utils/auth.ts b/ui/src/utils/auth.ts new file mode 100644 index 0000000..6495edb --- /dev/null +++ b/ui/src/utils/auth.ts @@ -0,0 +1,61 @@ +import type { Captcha } from './common' +import { + getCaptcha, + getLocalStorage, + getToken, + removeLocalStorage, + setLocalStorage, + setToken +} from './common' +import { TOKEN_NAME } from '@/constants/Common.constants' +import _ from 'lodash' +import request from '@/services' + +let captcha: Captcha + +async function login(username: string, passwd: string): Promise { + removeLocalStorage('username') + await request.post('/login', { username, passwd }).then((res: any) => { + const response = res.data + if (response.code === 20010) { + setToken(response.data.token) + } + }) + + return !_.isEmpty(getToken()) +} + +function logout(): void { + removeLocalStorage(TOKEN_NAME) + removeLocalStorage('username') +} + +function getLoginStatus(): boolean { + return getLocalStorage(TOKEN_NAME) != null +} + +async function getUsername(): Promise { + if (!_.isEmpty(getLocalStorage('username'))) { + return getLocalStorage('username') + } + + let username = '' + + await request.get('/userInfo').then((res) => { + username = res.data.data.user.username + }) + + setLocalStorage('username', username) + return username +} + +function getCaptchaSrc(): string { + captcha = getCaptcha(300, 150, 4) + return captcha.base64Src +} + +function verifyCaptcha(value: string): boolean { + return captcha.value === value.replace(/\s*/g, '').toUpperCase() +} + +export { login, logout, getLoginStatus, getUsername, getCaptchaSrc, verifyCaptcha } diff --git a/ui/src/utils/common.ts b/ui/src/utils/common.ts index e69de29..d37d57c 100644 --- a/ui/src/utils/common.ts +++ b/ui/src/utils/common.ts @@ -0,0 +1,153 @@ +import { TOKEN_NAME } from '@/constants/Common.constants' + +interface Captcha { + value: string + base64Src: string +} + +function getQueryVariable(variable: string): string | null { + const query = window.location.search.substring(1) + const vars = query.split('&') + for (let i = 0; i < vars.length; i++) { + const pair = vars[i].split('=') + if (pair[0] === variable) { + return decodeURIComponent(pair[1].replace(/\+/g, ' ')) + } + } + return null +} + +function setCookie( + name: string, + value: string, + daysToLive: number | null, + path: string | null +): void { + let cookie = name + '=' + encodeURIComponent(value) + + if (typeof daysToLive === 'number') { + cookie = `${cookie}; max-age=${daysToLive * 24 * 60 * 60}` + } + + if (typeof path === 'string') { + cookie += '; path=' + path + } + + document.cookie = cookie +} + +function setLocalStorage(name: string, value: string): void { + localStorage.setItem(name, value) +} + +function setToken(token: string): void { + setLocalStorage(TOKEN_NAME, token) +} + +function getCookie(name: string): string | null { + const cookieArr = document.cookie.split(';') + + for (let i = 0; i < cookieArr.length; i++) { + const cookiePair = cookieArr[i].split('=') + if (name === cookiePair[0].trim()) { + return decodeURIComponent(cookiePair[1]) + } + } + + return null +} + +function getLocalStorage(name: string): string | null { + return localStorage.getItem(name) +} + +function getToken(): string | null { + return getLocalStorage(TOKEN_NAME) +} + +function removeCookie(name: string): void { + document.cookie = name + '=; max-age=0' +} + +function removeLocalStorage(name: string): void { + localStorage.removeItem(name) +} + +function removeToken(): void { + removeLocalStorage(TOKEN_NAME) +} + +function randomInt(start: number, end: number): number { + if (start > end) { + const t = start + start = end + end = t + } + start = Math.ceil(start) + end = Math.floor(end) + return start + Math.floor(Math.random() * (end - start)) +} + +function randomFloat(start: number, end: number): number { + return start + Math.random() * (end - start) +} + +function randomColor(start: number, end: number): string { + return `rgb(${randomInt(start, end)},${randomInt(start, end)},${randomInt(start, end)})` +} + +function getCaptcha(width: number, high: number, num: number): Captcha { + const CHARTS = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'.split('') + + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d') as CanvasRenderingContext2D + + ctx.rect(0, 0, width, high) + ctx.clip() + + ctx.fillStyle = randomColor(200, 250) + ctx.fillRect(0, 0, width, high) + + for (let i = 0.05 * width * high; i > 0; i--) { + ctx.fillStyle = randomColor(0, 256) + ctx.fillRect(randomInt(0, width), randomInt(0, high), 1, 1) + } + + ctx.font = `${high - 4}px Consolas` + ctx.fillStyle = randomColor(160, 200) + let value = '' + for (let i = 0; i < num; i++) { + const x = ((width - 10) / num) * i + 5 + const y = high - 12 + const r = Math.PI * randomFloat(-0.12, 0.12) + const ch = CHARTS[randomInt(0, CHARTS.length)] + value += ch + ctx.translate(x, y) + ctx.rotate(r) + ctx.fillText(ch, 0, 0) + ctx.rotate(-r) + ctx.translate(-x, -y) + } + + const base64Src = canvas.toDataURL('image/jpg') + return { + value, + base64Src + } +} + +export type { Captcha } + +export { + getQueryVariable, + getCookie, + getLocalStorage, + getToken, + setCookie, + setLocalStorage, + setToken, + removeCookie, + removeLocalStorage, + removeToken, + getCaptcha +}