Java实战-实现动态菜单的方式

使用 Spring SecurityJWT 来实现动态菜单的步骤包括用户身份验证、生成和验证 JWT 令牌,以及根据用户的角色或权限动态生成菜单。这种实现方式需要你在后端进行身份认证和授权管理,并在前端根据用户信息动态展示菜单。

实现步骤

  1. 用户身份验证和 JWT 生成
  2. JWT 验证和授权
  3. 动态菜单生成

步骤 1: 用户身份验证和 JWT 生成

首先,用户通过登录接口提交用户名和密码进行身份验证,成功后生成 JWT 令牌返回给用户。

代码示例:

1.1 用户登录控制器

@RestController
public class AuthController {
    
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @PostMapping("/login")
    public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {
        // 进行用户身份认证
        Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(
                loginRequest.getUsername(),
                loginRequest.getPassword()
            )
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 生成JWT令牌
        String jwt = jwtTokenUtil.generateToken(authentication);
        return ResponseEntity.ok(new JwtResponse(jwt));
    }
}

1.2 JWT 工具类

@Component
public class JwtTokenUtil {

    private String jwtSecret = "yourSecretKey"; // 你的密钥

    public String generateToken(Authentication authentication) {
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + 86400000); // 设置令牌过期时间

        return Jwts.builder()
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
    }

    public String getUsernameFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(jwtSecret)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

步骤 2: JWT 验证和授权

在每个请求中通过 JWT 进行用户身份验证,验证成功后根据用户信息来确定用户的角色或权限。

代码示例:

2.1 JWT 过滤器

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = getJwtFromRequest(request);

        if (StringUtils.hasText(token) && jwtTokenUtil.validateToken(token)) {
            String username = jwtTokenUtil.getUsernameFromToken(token);

            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}

2.2 安全配置类

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = getJwtFromRequest(request);

        if (StringUtils.hasText(token) && jwtTokenUtil.validateToken(token)) {
            String username = jwtTokenUtil.getUsernameFromToken(token);

            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}

步骤 3: 动态菜单生成

用户成功登录后,后端根据用户的角色或权限生成相应的菜单数据,前端再根据这个数据渲染菜单。

代码示例:

3.1 获取菜单数据的控制器

@RestController
public class MenuController {

    @GetMapping("/menu")
    public ResponseEntity<?> getUserMenu(Authentication authentication) {
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        List<String> roles = userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList());

        // 根据用户角色生成菜单
        List<MenuItem> menuItems = generateMenuBasedOnRoles(roles);

        return ResponseEntity.ok(menuItems);
    }

    private List<MenuItem> generateMenuBasedOnRoles(List<String> roles) {
        // 这里根据角色生成动态菜单
        List<MenuItem> menuItems = new ArrayList<>();
        if (roles.contains("ROLE_ADMIN")) {
            menuItems.add(new MenuItem("Dashboard", "/dashboard"));
            menuItems.add(new MenuItem("User Management", "/users"));
        } else if (roles.contains("ROLE_USER")) {
            menuItems.add(new MenuItem("Profile", "/profile"));
            menuItems.add(new MenuItem("Orders", "/orders"));
        }
        return menuItems;
    }
}

3.2 菜单数据模型

public class MenuItem {
    private String name;
    private String url;

    public MenuItem(String name, String url) {
        this.name = name;
        this.url = url;
    }

    // Getter和Setter方法
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值