diff --git a/chaos_api_domain/src/main/java/cn/nopj/chaos_api/dto/FileUploadResponse.java b/chaos_api_domain/src/main/java/cn/nopj/chaos_api/dto/FileUploadResponse.java new file mode 100644 index 0000000..501a252 --- /dev/null +++ b/chaos_api_domain/src/main/java/cn/nopj/chaos_api/dto/FileUploadResponse.java @@ -0,0 +1,13 @@ +package cn.nopj.chaos_api.dto; + +import lombok.Data; + +@Data +public class FileUploadResponse { + private String fileName; + private String fileDownloadUri; + private String ossBucket; + private String fileOSSUri; + private String fileType; + private long size; +} diff --git a/chaos_api_interface/pom.xml b/chaos_api_interface/pom.xml index 2616d64..10ccaa0 100644 --- a/chaos_api_interface/pom.xml +++ b/chaos_api_interface/pom.xml @@ -25,6 +25,7 @@ chaos_api_domain ${project.version} + diff --git a/chaos_api_interface/src/main/java/cn/nopj/chaos_api/service/ImageService.java b/chaos_api_interface/src/main/java/cn/nopj/chaos_api/service/ImageService.java new file mode 100644 index 0000000..192405e --- /dev/null +++ b/chaos_api_interface/src/main/java/cn/nopj/chaos_api/service/ImageService.java @@ -0,0 +1,15 @@ +package cn.nopj.chaos_api.service; + + +import java.io.InputStream; + +public interface ImageService { + + /** + * 上传图片 + * @param fileName 文件名 + * @param content 文件内容 + * @return 文件路径 + */ + String uploadImage(String fileName, InputStream content); +} diff --git a/chaos_api_service/src/main/java/cn/nopj/chaos_api/service/impl/ImageServiceImpl.java b/chaos_api_service/src/main/java/cn/nopj/chaos_api/service/impl/ImageServiceImpl.java new file mode 100644 index 0000000..abf5924 --- /dev/null +++ b/chaos_api_service/src/main/java/cn/nopj/chaos_api/service/impl/ImageServiceImpl.java @@ -0,0 +1,17 @@ +package cn.nopj.chaos_api.service.impl; + +import cn.nopj.chaos_api.service.ImageService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.InputStream; + +@Slf4j +@Service +public class ImageServiceImpl implements ImageService { + @Override + public String uploadImage(String fileName, InputStream content) { + //todo 完成上传图片功能 + return ""; + } +} diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/config/jwt/JwtAuthenticationTokenFilter.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/config/jwt/JwtAuthenticationTokenFilter.java index 17f98fb..363bcbe 100644 --- a/chaos_api_web/src/main/java/cn/nopj/chaos_api/config/jwt/JwtAuthenticationTokenFilter.java +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/config/jwt/JwtAuthenticationTokenFilter.java @@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -17,6 +18,7 @@ import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.util.List; /** * JWT 登录授权过滤器 @@ -25,8 +27,6 @@ import java.io.IOException; @Slf4j public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { - @Autowired - private UserDetailsService userDetailsService; @Autowired private JwtTokenUtil jwtTokenUtil; @Value("${jwt.tokenHeader}") @@ -49,11 +49,19 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { log.info("username={}", username); // 如果 Token 中有用户名但上下文中没有,说明是首次登录 if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { - UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); + // 验证 Token 是否有效 - if (jwtTokenUtil.validateToken(authToken, userDetails)) { + if (jwtTokenUtil.validateToken(authToken)) { + + List authorityStrings = jwtTokenUtil.getAuthoritiesFromToken(authToken); + + List authorities = authorityStrings.stream() + .map(SimpleGrantedAuthority::new) + .toList(); + log.info("authorities: {}", authorities); UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + new UsernamePasswordAuthenticationToken(username, null, authorities); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/HLSController.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/HLSController.java new file mode 100644 index 0000000..8515fd9 --- /dev/null +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/HLSController.java @@ -0,0 +1,20 @@ +package cn.nopj.chaos_api.controller; + +import cn.nopj.chaos_api.model.ApiResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/api/hls") +public class HLSController { + + @PreAuthorize("hasAuthority('admin')") + @GetMapping("/") + ApiResult getHLS(){ + return ApiResult.success("HLS is radar"); + } +} \ No newline at end of file diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/ImageController.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/ImageController.java new file mode 100644 index 0000000..bb06729 --- /dev/null +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/ImageController.java @@ -0,0 +1,24 @@ +package cn.nopj.chaos_api.controller; + +import cn.nopj.chaos_api.model.ApiResult; +import cn.nopj.chaos_api.service.ImageService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@Slf4j +@RestController +@RequestMapping("/api/image") +public class ImageController { + @Autowired + private ImageService imageService; + + @RequestMapping("/upload") + ApiResult uploadImage(@RequestParam("file") MultipartFile file) { + log.info("上传图片"); + return ApiResult.success("上传成功"); + } +} diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/impl/UserDetailsServiceImpl.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/impl/UserDetailsServiceImpl.java index b5d31dc..aba8d0d 100644 --- a/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/impl/UserDetailsServiceImpl.java +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/service/impl/UserDetailsServiceImpl.java @@ -3,6 +3,7 @@ package cn.nopj.chaos_api.service.impl; import cn.nopj.chaos_api.domain.entity.User; import cn.nopj.chaos_api.mapper.UserMapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -15,6 +16,7 @@ import java.util.List; import java.util.stream.Collectors; @Service +@Slf4j public class UserDetailsServiceImpl implements UserDetailsService { @Autowired @@ -30,6 +32,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { // 2. 查询该用户的权限信息 (角色 + 权限) List authorities = userMapper.findAuthoritiesByUsername(username); + log.info("用户权限列表: {}", authorities); // 3. 将权限字符串列表转换为 GrantedAuthority 集合 List grantedAuthorities = authorities.stream() .map(SimpleGrantedAuthority::new) diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/util/JwtTokenUtil.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/util/JwtTokenUtil.java index 416935c..6f89c3d 100644 --- a/chaos_api_web/src/main/java/cn/nopj/chaos_api/util/JwtTokenUtil.java +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/util/JwtTokenUtil.java @@ -6,12 +6,15 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Component; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; @Slf4j @@ -53,10 +56,9 @@ public class JwtTokenUtil { /** * 验证 Token 是否有效 */ - public boolean validateToken(String token, UserDetails userDetails) { + public boolean validateToken(String token) { try { - String username = getUsernameFromToken(token); - return username != null && username.equals(userDetails.getUsername()) && !isTokenExpired(token); + return decodeToken(token) != null; } catch (Exception e) { return false; } @@ -69,10 +71,17 @@ public class JwtTokenUtil { Date now = new Date(); Date expiryDate = new Date(now.getTime() + expiration * 1000); + List authorities = userDetails.getAuthorities() + .stream() + .map(GrantedAuthority::getAuthority) + .toList(); + + return JWT.create() .withSubject(userDetails.getUsername()) .withIssuedAt(now) .withExpiresAt(expiryDate) + .withClaim("authorities", authorities) .sign(algorithm); } @@ -86,4 +95,34 @@ public class JwtTokenUtil { } } + + /** + * 解析 Token + * @param token Token + * @return 解析后的 Token + */ + private DecodedJWT decodeToken(String token) { + try { + return JWT.decode(token); + } catch (Exception e) { + return null; + } + } + + + /** + * 从 Token 中获取权限列表 + * @param token Token + * @return 权限列表 + */ + public List getAuthoritiesFromToken(String token){ + DecodedJWT decodedJWT = decodeToken(token); + if (decodedJWT == null){ + return null; + } + return decodedJWT.getClaim("authorities") + .asList(String.class); + + } + }