leniu-security-guard

所有注解包路径:net.xnzn.framework.secure.filter.annotation.*

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "leniu-security-guard" with this command: npx skills add xu-cell/ai-engineering-init/xu-cell-ai-engineering-init-leniu-security-guard

leniu-security-guard

认证注解

所有注解包路径:net.xnzn.framework.secure.filter.annotation.*

注解 用途

@RequiresAuthentication

需要登录认证(最常用,类/方法级)

@RequiresGuest

允许游客访问(公开接口)

@RequiresPermissions

需要指定权限码

@RequiresRoles

需要指定角色

@RequiresUser

需要用户登录

@RequiresHeader

需要指定请求头

Controller 认证示例

import net.xnzn.framework.secure.filter.annotation.RequiresAuthentication; import net.xnzn.framework.secure.filter.annotation.RequiresGuest; import net.xnzn.framework.secure.filter.annotation.RequiresPermissions; import net.xnzn.framework.secure.filter.annotation.RequiresRoles;

// 类级别:整个 Controller 需要登录 @RestController @RequestMapping("/api/v2/web/xxx") @RequiresAuthentication public class XxxWebController { }

// 方法级别:允许游客访问 @GetMapping("/public/info") @RequiresGuest public LeResponse<String> getPublicInfo() { }

// 需要特定权限 @GetMapping("/admin/users") @RequiresPermissions("system:user:list") public LeResponse<List<User>> listUsers() { }

// AND 逻辑(默认):需要所有权限 @RequiresPermissions(value = {"system:user:add", "system:user:edit"}, logical = Logical.AND)

// OR 逻辑:需要任一权限 @RequiresPermissions(value = {"system:user:add", "system:user:edit"}, logical = Logical.OR)

// 需要指定角色 @RequiresRoles("admin")

// 需要所有角色 @RequiresRoles(value = {"admin", "manager"}, logical = Logical.AND)

注意:@RequiresPermissions 不指定 value 时,自动使用 @RequestMapping 路径作为权限码。

TokenManager API

import net.xnzn.framework.secure.token.TokenManager;

用户信息

// 登录状态 TokenManager.isLogin();

// 用户 ID Long userId = TokenManager.getSubjectId().orElse(null);

// 用户名 String userName = TokenManager.getSubjectName().orElse(null);

// 附加数据 Map<String, String> userData = TokenManager.getSubjectData(); String orgId = userData.get("orgId");

权限/角色校验

// 单个权限 TokenManager.hasPermission("system:user:add");

// 多个权限(AND) TokenManager.hasPermission("system:user:add", "system:user:edit");

// 任一权限(OR) TokenManager.hasAnyPermission("system:user:add", "system:user:edit");

// 角色 TokenManager.hasRole("admin"); TokenManager.hasAnyRole("admin", "manager");

附加数据管理

// 添加 TokenManager.attachData("orgId", "12345");

// 批量添加 TokenManager.attachData(Map.of("orgId", "12345", "deptId", "67890"));

// 获取 String orgId = TokenManager.getSubjectData().get("orgId");

// 移除 TokenManager.removeData("orgId", "deptId");

登出与缓存

// 登出 TokenManager.logout();

// 强制下线 TokenManager.revokeAuthenticate();

// 撤销旧 Token(保留最近 N 个) TokenManager.revokeAuthenticate(userId, 3);

// 清除权限/角色缓存 TokenManager.clearPermission(userId); TokenManager.clearRole(userId); TokenManager.clearRoleAndPermission(userId); TokenManager.clearAllRoleAndPermission();

WebContext

import net.xnzn.framework.secure.WebContext;

HttpServletRequest request = WebContext.get().getRequest().orElse(null); HttpServletResponse response = WebContext.get().getResponse().orElse(null); Optional<AccessToken> token = WebContext.get().getAccessToken();

// 属性存取 WebContext.get().setAttribute("key", "value"); Object value = WebContext.get().getAttribute("key"); WebContext.reset();

数据权限校验(防越权)

@Transactional(rollbackFor = Exception.class) public void delete(Long id) { Order order = orderMapper.selectById(id); Assert.notNull(order, () -> new LeException("订单不存在"));

// 校验数据归属
Long currentUserId = TokenManager.getSubjectId()
    .orElseThrow(() -> new LeException("用户未登录"));
if (!order.getUserId().equals(currentUserId)) {
    throw new LeException("无权操作该订单");
}

orderMapper.deleteById(id);

}

最小权限原则

@RequiresAuthentication @RequiresPermissions("order:view") public PageVO<OrderVO> pageList(OrderPageParam param) { Long userId = TokenManager.getSubjectId() .orElseThrow(() -> new LeException("用户未登录")); param.setUserId(userId); // 限制只查自己的数据 return orderService.pageList(param); }

SQL 注入防护

MyBatis XML 必须用 #{}

<!-- 正确:参数化查询 --> <select id="selectByName" resultType="User"> SELECT id, name, mobile FROM user WHERE name = #{name} </select>

<!-- 错误:${} 有注入风险 --> <select id="selectByName" resultType="User"> SELECT * FROM user WHERE name = '${name}' </select>

禁止 SELECT *

<!-- 错误 --> SELECT * FROM user WHERE status = #{status}

<!-- 正确:明确指定字段 --> SELECT id, name, mobile, status FROM user WHERE status = #{status}

VO 敏感字段处理

@Data public class UserVO { @JsonIgnore private String password; // 密码绝不返回

@JsonSerialize(using = MobileSerializer.class)
private String mobile;    // 手机号脱敏

@JsonSerialize(using = IdCardSerializer.class)
private String idCard;    // 身份证脱敏

}

日志脱敏

// 错误:记录敏感信息 log.info("用户登录, username:{}, password:{}", username, password);

// 正确:不记录密码 log.info("用户登录, username:{}", username);

输入验证

@Data public class UserParam { @NotBlank(message = "用户名不能为空") @Pattern(regexp = "^[a-zA-Z0-9_]{4,20}$", message = "用户名格式不正确") private String username;

@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码长度必须在6-20之间")
private String password;

@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String mobile;

@Email(message = "邮箱格式不正确")
private String email;

}

限流防护

// Redis 计数器限流 public void checkRateLimit(Long userId, String api, int limit, int seconds) { String key = String.format("rate:%d:%s", userId, api); Integer count = RedisUtil.incr(key, (long) seconds); if (count > limit) { throw new LeException("请求过于频繁,请稍后重试"); } }

注意事项

  • 权限和角色数据自动缓存到 Redis,通过 clearPermission/clearRole 手动清除

  • TokenManager 方法需在已登录上下文中使用

  • @RequiresGuest 用于公开接口,不需要登录

  • MyBatis XML 中必须使用 #{} 而非 ${}

  • VO 中密码字段必须 @JsonIgnore ,手机号等用序列化脱敏

  • 限流 key 格式:rate:{userId}:{api}

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

scheduled-jobs

No summary provided by upstream source.

Repository SourceNeeds Review
General

loki-log-query

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

api-development

No summary provided by upstream source.

Repository SourceNeeds Review
General

brainstorm

No summary provided by upstream source.

Repository SourceNeeds Review