权限校验—接口检验

一、背景介绍

最近项目中要实现根据不同用户去划分不同的角色,而不同角色具备调用不同接口的权限这个功能。用户在调用接口时需要校验用户是否具有权限访问接口,防止外界恶意调用随意篡改


二、思路&方案

为什么要进行接口鉴权?

  1. 接口鉴权可以提供对接口访问的监控和追踪功能。通过记录和审计用户对接口的访问情况,可以及时发现异常行为和安全威胁,并采取相应的措施进行应对。
  2. 通过接口鉴权,可以限制对敏感数据的访问。只有具有相应权限的用户或应用程序才能获取敏感数据,从而保护数据的机密性和完整性。
  3. 接口鉴权可以实现对接口的细粒度访问控制。根据用户的身份、角色、权限等级等,可以控制用户对接口的不同操作和功能的访问权限,确保只有有权用户可以执行相应的操作。

接口鉴权是保证系统安全、数据保护和访问控制的重要机制,防止未经授权的访问、滥用和数据泄露,提高系统的安全性和可靠性。

@PerAuthorizre权限注解

作用:方法前拦截判断是否具备权限,用来控制被注解标记的类或方法是否能够被调用

好处

  1. 安全性增强:只有经过授权的用户才能执行带有 @PerAuthorizr 注解的代码,从而减少了潜在的安全漏洞和攻击风险。

  2. 标记权限:通过使用 @PerAuthorizr 注解,可以明确地标记哪些代码需要特定的权限才能执行。这有助于开发人员更好地了解代码的权限需求,并确保只有具有相应权限的用户或角色可以访问该代码。

底层实现

  1. 底层实现可能会使用 AOP 技术。通过 AOP,可以在代码执行之前或之后,根据注解的参数进行权限验证和授权操作。
  2. 可能会使用拦截器或过滤器来拦截请求,并进行权限验证和授权操作。拦截器或过滤器可以在请求到达目标代码之前对请求进行预处理,包括检查用户的权限和身份验证。
  3. 可能会使用缓存机制。通过缓存用户的权限信息,可以避免频繁地进行权限查询和验证,提高系统的响应速度。

使用

@PreAuthorize("")

调用别名为ss类的hasPermi方法,并传入参数

@ss注解

作用:自定义,定义了权限校验流程

结果:返回true则鉴权成功,false则返回403说明没有权限

使用

@ss.hasPermi('system:role:list')

调用别名为ss类的hasPermi方法,并传入参数

逻辑校验流程

第一步、定义@ss类,并添加hasPermi校验方法

  1.         获取传入用户的信息
  2.         判断用户信息的权限信息集合中是否含有定义的权限

第二步、在要鉴权的接口上添加@PreAuthorizez注解


三、过程

NS图

引入依赖

<!-- spring security 安全认证 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.5.8</version>
</dependency>

定义@ss类,并添加hasPermi校验方法

package com.example;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Set;

/**
 * @BelongsPackage: com.example
 * @Description: 自定义权限实现
 * @Version: 1.0
 */
@Service("ss")
public class PermissionService {
    /** 所有权限标识 */
    private static final String ALL_PERMISSION = "*:*:*";


    /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    public boolean hasPermi(String permission) throws Exception {
        //判断是否传入权限字符
        if ( StringUtils.isEmpty(permission))
        {
            return false;
        }
        //获取用户信息
        LoginUser loginUser = SecurityUtils.getLoginUser();
        //判断是否有用户信息,或者用户信息中是否包含权限集合
        if ( StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
        {
            return false;
        }
        //将权限设置到请求头中
        PermissionContextHolder.setContext(permission);
        //判断是否包含权限
        return hasPermissions(loginUser.getPermissions(), permission);
    }

    /**
     * 判断是否包含权限
     *
     * @param permissions 权限列表
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    private boolean hasPermissions(Set<String> permissions, String permission)
    {
        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
    }
}

字符串工具类

package com.example;

/**
 * @BelongsPackage: com.example
 * @Description: 字符串工具类
 * @Version: 1.0
 */
public  class StringUtils {
    /** 空字符串 */
    private static final String NULLSTR = "";

    /**
     * * 判断一个对象是否为空
     * @return true:为空 false:非空
     */
    public static boolean isNull(Object object)
    {
        return object == null;
    }

    /**
     * * 判断一个字符串是否为空串
     * @return true:为空 false:非空
     */
    public static boolean isEmpty(String str)
    {
        return isNull(str) || NULLSTR.equals(str.trim());
    }


    /**
     * 去空格
     */
    public static String trim(String str)
    {
        return (str == null ? "" : str.trim());
    }
}

权限信息

package com.example;

import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

/**
 * @BelongsPackage: com.example
 * @Description: TODO
 * @Version: 1.0
 */
public class PermissionContextHolder {
    private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";

    public static void setContext(String permission)
    {
        RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
                RequestAttributes.SCOPE_REQUEST);
    }

    public static String getContext()
    {
        return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
                RequestAttributes.SCOPE_REQUEST));
    }
}

安全服务工具类

package com.example;

import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

/**
 * @BelongsPackage: com.example
 * @Description: 安全服务工具类
 * @Version: 1.0
 */
public class SecurityUtils {
    /**
     * 获取用户
     **/
    public static LoginUser getLoginUser() throws Exception {
        try
        {
            return (LoginUser) getAuthentication().getPrincipal();
        }
        catch (Exception e)
        {
            throw new Exception("获取用户信息异常");
        }
    }

    /**
     * 获取Authentication
     */
    public static Authentication getAuthentication()
    {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}

登录用户身份权限

package com.example;

import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;

/**
 * @BelongsPackage: com.example
 * @Description: 登录用户身份权限
 * @Version: 1.0
 */
@Data
public class LoginUser implements UserDetails
{
    private static final long serialVersionUID = 1L;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 部门ID
     */
    private Long deptId;

    /**
     * 用户唯一标识
     */
    private String token;

    /**
     * 登录时间
     */
    private Long loginTime;

    /**
     * 过期时间
     */
    private Long expireTime;

    /**
     * 登录IP地址
     */
    private String ipaddr;

    /**
     * 登录地点
     */
    private String loginLocation;

    /**
     * 浏览器类型
     */
    private String browser;

    /**
     * 操作系统
     */
    private String os;

    /**
     * 权限列表
     */
    private Set<String> permissions;


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }
}


四、总结

本文章对@PerAuthorizre注解结合项目具体如何进行鉴权进行了详细分析,我们在项目使用的过程中除了知道怎么用,也要知其所以然。

如果大家想要了解 spring sercurity+token安全机制是如何做的权限认证和授权,关于SpringSecurity如何集成JWT做的认证授权大家可以参考这篇博主的文章:SpringSecurity集成JWT认证框架_jwt spring security_哆木的博客-CSDN博客

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小乔努力变强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值