SpringSecurity怎样使用注解控制权限

一般的系统在权限设计上,都会分为角色、权限(RDBC),复杂一点的可能会有用户组、组织之类的概念。

用户的权限是写死的,对应于后台的接口或者资源,是没办法改变的,一般不对用户开放修改权限。

管理员用户可以通过给角色分配权限的方式,来实现访问控制。

所以当我们写过滤器,或者用一些安全框架时(比如Shiro,Spring Security),也需要将可变的“角色”,转化为不可变的“权限”,注入到框架中。

具体的可以看我之前写的一篇(Spring Security整合jwt完整版)

注入当前用户的权限后,就需要进行访问控制了。

常见的做法有

1、路径比对

之前有个项目用过一次,定义一个过滤器,添加到security的过滤链中,在这个过滤器中做这么一件事:

分析当前访问路径所需要的权限,检查当前用户是否具有该权限,做一个对比,根据对比结果来决定当前用户是否可以访问该资源。

这种做法的好处是代码的入侵性不高,不需要再每个接口上加注解。但相对来说,显得不那么直观,可读性比较差,所以这次换个方法。

2、使用注解的方式

SpringSecurity使用注解来控制访问时,需要提前开启这个功能。

在配置类上加上注解

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

在接口中如此使用

   /**
     * 条件查询
     */
    @PreAuthorize("hasAuthority('IMPORT:SELECT')")
    @ApiOperation(value = "查询")
    @GetMapping("/list")
    public R<Page<Task>> list(TaskDto taskDto){
        //测试阶段,随机生成任务
        Random random = new Random();

        //todo
        int i = random.nextInt(4);
        if(i == 2) {
            metroServerAdapterService.reloadShelveTask();
        }
        Page<Task> list = taskService.list(taskDto);
        return R.ok(list);
    }

hasAuthority可以替换成hasRole,虽然可以达到相同的目的,但是在使用的方法上还是有些不同的。

hasRole要求内容必须以"ROLE_"开头,也是官方推荐的命名方式,否则没有效果。但是hasAuthority没有限制,数据库中怎样写的,代码里就怎么写。

同样的功能的注解为什么要有两个名字呢。或许这么做可能在语义上比较清晰明确一点,将角色与权限这两个概念稍加区分。

仔细想一下,确实有些小型的系统或许压根就不需要权限,只有给用户分配角色,没有给角色分配权限这一过程。这样的话,角色也是不可变的,就可以根据角色来做访问控制了。

但考虑通用性,个人觉得用hasAuthority就可以了。

SpringSecurity_权限注解@PreAuthorize、@PostAuthorize

spring是如何实现对HTTP请求进行安全检查和资源使用授权的?

实现过程由类AbstractSecurityInterceptor在beforeInvocation方法中完成,在beforeInvocation的实现中,

首先,需要读取IoC容器中Bean的配置,在这些属性配置中配置了对HTTP请求资源的安全需求,

比如,哪个角色的用户可以接入哪些URL请求资源,具体实现逻辑见:

#与Web环境的接口FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter

@PreAuthorize、@PostAuthorize注解实现逻辑

继承根节点:SecurityMetaSource

可以通过Spring注解声明,需要依赖类注入,实现权限灵活配置如:

@Component("securityMetadataSource")
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource
PrePostAnnotationSecurityMetadataSource类继承关系
AbstractMethodSecurityMetadataSource类继承关系
package org.springframework.security.access.prepost;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.method.AbstractMethodSecurityMetadataSource;
import org.springframework.util.ClassUtils;
public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
    private final PrePostInvocationAttributeFactory attributeFactory;
    public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) {
        this.attributeFactory = attributeFactory;
    }

    public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
        if (method.getDeclaringClass() == Object.class) {
            return Collections.emptyList();
        } else {
            this.logger.trace("Looking for Pre/Post annotations for method '" + method.getName() + "' on target class '" + targetClass + "'");
            PreFilter preFilter = (PreFilter)this.findAnnotation(method, targetClass, PreFilter.class);
            PreAuthorize preAuthorize = (PreAuthorize)this.findAnnotation(method, targetClass, PreAuthorize.class);
            PostFilter postFilter = (PostFilter)this.findAnnotation(method, targetClass, PostFilter.class);
            PostAuthorize postAuthorize = (PostAuthorize)this.findAnnotation(method, targetClass, PostAuthorize.class);
            if (preFilter == null && preAuthorize == null && postFilter == null && postAuthorize == null) {
                this.logger.trace("No expression annotations found");
                return Collections.emptyList();
            } else {
                String preFilterAttribute = preFilter == null ? null : preFilter.value();
                String filterObject = preFilter == null ? null : preFilter.filterTarget();
                String preAuthorizeAttribute = preAuthorize == null ? null : preAuthorize.value();
                String postFilterAttribute = postFilter == null ? null : postFilter.value();
                String postAuthorizeAttribute = postAuthorize == null ? null : postAuthorize.value();
                ArrayList<ConfigAttribute> attrs = new ArrayList(2);
                PreInvocationAttribute pre = this.attributeFactory.createPreInvocationAttribute(preFilterAttribute, filterObject, preAuthorizeAttribute);
                if (pre != null) {
                    attrs.add(pre);
                }

                PostInvocationAttribute post = this.attributeFactory.createPostInvocationAttribute(postFilterAttribute, postAuthorizeAttribute);
                if (post != null) {
                    attrs.add(post);
                }

                attrs.trimToSize();
                return attrs;
            }
        }
    }

    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    private <A extends Annotation> A findAnnotation(Method method, Class<?> targetClass, Class<A> annotationClass) {
        Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
        A annotation = AnnotationUtils.findAnnotation(specificMethod, annotationClass);
        if (annotation != null) {
            this.logger.debug(annotation + " found on specific method: " + specificMethod);
            return annotation;
        } else {
            if (specificMethod != method) {
                annotation = AnnotationUtils.findAnnotation(method, annotationClass);
                if (annotation != null) {
                    this.logger.debug(annotation + " found on: " + method);
                    return annotation;
                }
            }

            annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass);
            if (annotation != null) {
                this.logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());
                return annotation;
            } else {
                return null;
            }
        }
    }
}
//注解开启权限
@EnableResourceServer
@EnableGlobalMethodSecurity
SecurityContextHolder作为全局缓存,从上下文获取授权信息
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

上面权限列表初始化由具体实现类实现:

public class User implements UserDetails, CredentialsContainer {
    ...
    private final Set<GrantedAuthority> authorities;
    ...
    //authorities权限列表
    public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        this(username, password, true, true, true, true, authorities);
    }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详解Spring Security 中的四种权限控制方式

    Spring Security 中对于权限控制默认已经提供了很多了,但是,一个优秀的框架必须具备良好的扩展性,恰好,Spring Security 的扩展性就非常棒,我们既可以使用 Spring Security 提供的方式做授权,也可以自定义授权逻辑.一句话,你想怎么玩都可以! 今天松哥来和大家介绍一下 Spring Security 中四种常见的权限控制方式. 表达式控制 URL 路径权限 表达式控制方法权限 使用过滤注解 动态权限 四种方式,我们分别来看.  1.表达式控制 URL 路径权

  • SpringSecurity权限控制实现原理解析

    菜单控制: 可以用来判断这个用户是不是有这些角色,没有的话就不展示 数据控制: 由于数据都是从后端查的,在后端控制权限就可以了 <!-- 开启权限控制注解支持 jsr250-annotations="enabled"表示支持jsr250-api的注解,需要jsr250-api的jar包 pre-post-annotations="enabled"表示支持spring表达式注解 secured-annotations="enabled"这才是

  • 基于Spring Security前后端分离的权限控制系统问题

    目录 1. 引入maven依赖 2. 建表并生成相应的实体类 3. 自定义UserDetails 4. 自定义各种Handler 5. Token处理 6. 访问控制 7. 配置WebSecurity 8. 看效果 9. 补充:手机号+短信验证码登录 前后端分离的项目,前端有菜单(menu),后端有API(backendApi),一个menu对应的页面有N个API接口来支持,本文介绍如何基于Spring Security前后端分离的权限控制系统问题. 话不多说,入正题.一个简单的权限控制系统需要

  • SpringBoot如何通过自定义注解实现权限检查详解

    前言 最近开发了一个接口,完成后准备自测时,却被拦截器拦截了,提示:(AUTH-NO)未能获得有效的请求参数!怎么会这样呢? 于是我全局搜了这个提示语,结果发现它被出现在一个Aspect类当中了,并且把一个 @interface 作为了一个切点,原来这里利用了Spring AOP面向切面的方式进行权限控制. SpringBoot通过自定义注解实现日志打印可参考:SpringBoot通过自定义注解实现日志打印 正文 Spring AOP Spring AOP 即面向切面,是对OOP面向对象的一种延

  • SpringBoot2.0 整合 SpringSecurity 框架实现用户权限安全管理方法

    一.Security简介 1.基础概念 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring的IOC,DI,AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为安全控制编写大量重复代码的工作. 2.核心API解读 1).SecurityContextHolder 最基本的对象,保存着当前会话用户认证,权限,鉴权等核心数据.Secu

  • SpringSecurity怎样使用注解控制权限

    一般的系统在权限设计上,都会分为角色.权限(RDBC),复杂一点的可能会有用户组.组织之类的概念. 用户的权限是写死的,对应于后台的接口或者资源,是没办法改变的,一般不对用户开放修改权限. 管理员用户可以通过给角色分配权限的方式,来实现访问控制. 所以当我们写过滤器,或者用一些安全框架时(比如Shiro,Spring Security),也需要将可变的"角色",转化为不可变的"权限",注入到框架中. 具体的可以看我之前写的一篇(Spring Security整合jw

  • Spring Boot 通过AOP和自定义注解实现权限控制的方法

    本文介绍了Spring Boot 通过AOP和自定义注解实现权限控制,分享给大家,具体如下: 源码:https://github.com/yulc-coding/java-note/tree/master/aop 思路 自定义权限注解 在需要验证的接口上加上注解,并设置具体权限值 数据库权限表中加入对应接口需要的权限 用户登录时,获取当前用户的所有权限列表放入Redis缓存中 定义AOP,将切入点设置为自定义的权限 AOP中获取接口注解的权限值,和Redis中的数据校验用户是否存在该权限,如果R

  • SpringBoot如何整合Springsecurity实现数据库登录及权限控制

    目录 第一步 第二步是封装一个自定义的类 第三步, 我们需要判断密码啦 总结 我们今天使用SpringBoot来整合SpringSecurity,来吧,不多BB 首先呢,是一个SpringBoot 项目,连接数据库,这里我使用的是mybaties.mysql, 下面是数据库的表 DROP TABLE IF EXISTS `xy_role`; CREATE TABLE `xy_role` ( `xyr_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键i

  • SpringBoot整合Security安全框架实现控制权限

    目录 一.前言 介绍: 官网: 优缺点: 案例: 二.环境准备 2.1.数据库表 2.2.导入依赖 2.3.配置文件 2.4.WebSecurityConfig Security的主要配置类: 2.5.Security身份验证 2.6.Security授权 2.7.UserDetailsService 2.7.MacLoginUrlAuthenticationEntryPoint 2.8.MyAccessDeniedHandler 2.9.MyLogoutSuccessHandler 2.10.

  • SpringMVC实现注解式权限验证的实例

    对大部分系统来说都需要权限管理来决定不同用户可以看到哪些内容,那么如何在Spring MVC中实现权限验证呢?当然我们可以继续使用servlet中的过滤器Filter来实现.但借助于Spring MVC中的action拦截器我们可以实现注解式的权限验证. 一.首先介绍一下action拦截器: HandlerInterceptor是Spring MVC为我们提供的拦截器接口,来让我们实现自己的处理逻辑,HandlerInterceptor 的内容如下: public interface Handl

  • SpringBoot使用自定义注解实现权限拦截的示例

    本文介绍了SpringBoot使用自定义注解实现权限拦截的示例,分享给大家,具体如下: HandlerInterceptor(处理器拦截器) 常见使用场景 日志记录: 记录请求信息的日志, 以便进行信息监控, 信息统计, 计算PV(page View)等 性能监控: 权限检查: 通用行为: 使用自定义注解实现权限拦截 首先HandlerInterceptor了解 在HandlerInterceptor中有三个方法: public interface HandlerInterceptor { //

  • Java位掩码控制权限与(&)或(|)非(~)、>的介绍

    1. java 位掩码 java 位掩码,在java开发中很少有场景会用到掩码,但是当系统中需要判断某个对象是否有 某些权限时,可以通过位掩码来做. 位掩码 主要通过位运算,例如与(&).非(~).或(|).异或(^).移位(<<和>>)等来实现 权限判断功能. 1.1 简单介绍一下位运算符(计算均为二进制计算) << : 左移运算符,num << 1,相当于num乘以2 >> : 右移运算符,num >> 1,相当于num除

  • SpringBoot基于SpringSecurity表单登录和权限验证的示例

    一.简介 上篇介绍了一个自己做的管理系统,最近空闲的时间自己在继续做,把之前登录时候自定义的拦截器过滤器换成了基于SpringSecurity来做,其中遇到了很多坑,总结下,大家有遇到类似问题的话就当是为大家闭坑吧. 二.项目实现功能和成果展示 首先来看下登录界面:这是我输入的一个正确的信息,点击登录后SpringSecurity会根据你输入的用户名和密码去验证是否正确,如果正确的话就去你定义的页面,我这里定义的是查询教师信息页面.来看下代码吧. 三.准备工作(前台页面.实体类) 实体类Teac

  • MySQL如何利用DCL管理用户和控制权限

    DCL(Data Control Language):数据控制语言,用来定义数据库的访问权限和安全级别,及创建用户. 一.管理用户 1.创建用户 -- 创建用户 CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码'; CREATE USER 'Summerday'@'localhost' IDENTIFIED BY '123456'; ps:如果出现了[The MySQL server is running with the --skip-grant-tables

随机推荐