返回顶部
首页 > 资讯 > 后端开发 > Python >SpringSecurity实现基于角色的访问控制框架
  • 797
分享到

SpringSecurity实现基于角色的访问控制框架

SpringSecurity访问控制框架SpringSecurity访问控制 2023-05-17 08:05:56 797人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录说明spring Security与shiro的区别简单使用登录校验流程引入Security设置用户名和密码使用配置类过滤规则授权方式WEB授权方法授权顺序优先级登出跨域认证失败

说明

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。Spring Security是一个专注于为Java应用程序提供身份验证和授权的框架。与所有Spring项目一样,Spring安全性的真正威力在于它可以很容易地扩展以满足定制需求。

一般Web应用的需要进行认证和授权。

  • 用户认证(Authentication):验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户。
  • 用户授权(Authorization):经过认证后判断当前用户是否有权限进行某个操作。在一个系统中,不同用户所具有的权限是不同的。

Spring Security与Shiro的区别

Spring Security 是 Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。相对于Shiro,在ssh/SSM中整合Spring Security都是比较麻烦的操作,但有了Spring Boot之后,Spring Boot 对于 Spring Security 提供了 自动化配置方案,可以零配置使用 Spring Security。因此,一般来说常见的安全管理技术栈组合是:

  • SSM+Shiro
  • Spring Boot /Spring Clound +Spring Security

简单使用

登录校验流程

引入Security

SpringBoot项目中使用SpringSecurity只需要引入依赖即可。

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

设置用户名和密码

在application.properties中添加属性:

server.port=8080
#spring.security.user.name=root
#spring.security.user.passWord=123456
#Mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

但是在application.properties中添加属性意味着登录系统的用户名的密码都是固定的,不推荐。可以使用配置类,在配置类中设置,配置类的优先级更高。

使用配置类

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;
    
    @Autowired
    private LoGoutSuccessHandlerImpl logoutSuccessHandler;
    
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;
    
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception
    {
        return super.authenticationManagerBean();
    }
    
    @Override
    protected void configure(httpsecurity HttpSecurity) throws Exception
    {
        httpSecurity
                // CRSF禁用,因为不使用session
                .csrf().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 允许匿名访问
                .antMatchers("/login").anonymous()
                .antMatchers(
                        HttpMethod.GET,
                        "*.html",
                        "*.CSS",
                        "/file*.js"
                ).permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                .headers().frameOptions().disable();
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
    
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }
}
  • @EnableGlobalMethodSecurity :当我们想要开启spring方法级安全时,只需要在任何 @Configuration实例上使用 @EnableGlobalMethodSecurity 注解就能达到此目的。
  • prePostEnabled = true 会解 @PreAuthorize 和 @PostAuthorize 两个注解。从名字就可以看出@PreAuthorize 注解会在方法执行前进行验证,而 @PostAuthorize 注解会在方法执行后进行验证。

@Service("ss")
public class PermissionService
{
    
    private static final String ALL_PERMISSION = "*:*:*";
    
    private static final String SUPER_ADMIN = "admin";
    private static final String ROLE_DELIMETER = ",";
    private static final String PERMISSION_DELIMETER = ",";
    @Autowired
    private TokenService tokenService;
    
    public boolean hasPermi(String permission)
    {
        if (StringUtils.isEmpty(permission))
        {
            return false;
        }
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
        {
            return false;
        }
        return hasPermissions(loginUser.getPermissions(), permission);
    }
    
    public boolean lacksPermi(String permission)
    {
        return hasPermi(permission) != true;
    }
    
    public boolean hasAnyPermi(String permissions)
    {
        if (StringUtils.isEmpty(permissions))
        {
            return false;
        }
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
        {
            return false;
        }
        Set<String> authorities = loginUser.getPermissions();
        for (String permission : permissions.split(PERMISSION_DELIMETER))
        {
            if (permission != null && hasPermissions(authorities, permission))
            {
                return true;
            }
        }
        return false;
    }
    
    public boolean hasRole(String role)
    {
        if (StringUtils.isEmpty(role))
        {
            return false;
        }
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
        {
            return false;
        }
        for (SysRole sysRole : loginUser.getUser().getRoles())
        {
            String roleKey = sysRole.getRoleKey();
            if (SUPER_ADMIN.contains(roleKey) || roleKey.contains(StringUtils.trim(role)))
            {
                return true;
            }
        }
        return false;
    }
    
    public boolean lacksRole(String role)
    {
        return hasRole(role) != true;
    }
    
    public boolean hasAnyRoles(String roles)
    {
        if (StringUtils.isEmpty(roles))
        {
            return false;
        }
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
        {
            return false;
        }
        for (String role : roles.split(ROLE_DELIMETER))
        {
            if (hasRole(role))
            {
                return true;
            }
        }
        return false;
    }
    
    private boolean hasPermissions(Set<String> permissions, String permission)
    {
        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
    }
}
    
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysUser user)
    {
        startPage();
        List<SysUser> list = userService.selectUserList(user);
        return getDataTable(list);
    }
  • antMatchers():可传入多个String参数,用于匹配多个请求api。结合permitAll(),可同时对多个请求设置忽略认证。
  • and():用于表示上一项配置已经结束,下一项配置将开始。

创建一个Service文件用于Security查询用户信息:

@Service
public class UserDetailsServiceImpl implements UserDetailsService
{
    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
    @Autowired
    private ISysUserService userService;
    @Autowired
    private SysPermissionService permissionService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    {
    	// 根据账户号查询用户信息
        SysUser user = userService.selectUserByUserName(username);
        if (StringUtils.isNull(user))
        {
            log.info("登录用户:{} 不存在.", username);
            throw new UsernameNotFoundException("登录用户:" + username + " 不存在");
        }
        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
        {
            log.info("登录用户:{} 已被删除.", username);
            throw new BaseException("对不起,您的账号:" + username + " 已被删除");
        }
        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
        {
            log.info("登录用户:{} 已被停用.", username);
            throw new BaseException("对不起,您的账号:" + username + " 已停用");
        }
        return createLoginUser(user);
    }
    public UserDetails createLoginUser(SysUser user)
    {
    	// 获取用户权限
        return new LoginUser(user, permissionService.getMenuPermission(user));
    }
}

当用户请求时,Security便会拦截请求,取出其中的username字段,从Service中查询该账户,并将信息填充到一个userDetails对象中返回。这样Security便拿到了填充后的userDetails对象,也就是获取到了包括权限在内的用户信息。

过滤规则

WebSecurityConfigurerAdapter.configure(HttpSecurity http)

授权方式

Security的授权方式有两种:

  • WEB授权(基于请求URL),在configure(HttpSecurity httpSecurity)中设置。
  • 方法授权(在方法上使用注解授权)

WEB授权

@Override
httpSecurity.authorizeRequests() // 对请求进行授权
    .antMatchers("/test1").hasAuthority("p1") // 设置/test1接口需要p1权限
    .antMatchers("/test2").hasAnyRole("admin", "manager") // 设置/test2接口需要admin或manager角色
    .and()
    .headers().frameOptions().disable();

其中:

  • hasAuthority(“p1”)表示需要p1权限
  • hasAnyAuthority(“p1”, “p2”)表示p1或p2权限皆可

同理:

  • hasRole(“p1”)表示需要p1角色
  • hasAnyRole(“p1”, “p2”)表示p1或p2角色皆可

方法授权

    
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysUser user)
    {
        startPage();
        List<SysUser> list = userService.selectUserList(user);
        return getDataTable(list);
    }

顺序优先级

校验是按照配置的顺序从上往下进行。若某个条件已匹配过,则后续同条件的匹配将不再被执行。也就是说,若多条规则是相互矛盾的,则只有第一条规则生效。典型地:

// 只有具有权限a的用户才能访问/get/resource
httpSecurity.authorizeRequests()
    .antMatchers("/get/resource").hasAuthority("a")
    .anyRequest().permitAll();
// 所有用户都能访问/get/resource
httpSecurity.authorizeRequests()
    .anyRequest().permitAll()
    .antMatchers("/get/resource").hasAuthority("a");

但若是包含关系,则需要将细粒度的规则放在前面:

// /get/resource需要权限a,除此之外所有的/get
@Configuration
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
{
    @Autowired
    private TokenService tokenService;
    
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException
    {
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser))
        {
            String userName = loginUser.getUsername();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
        }
        ServletUtils.renderString(response, JSON.toJSONString(ajaxResult.error(HttpStatus.SUCCESS, "退出成功")));
    }
}

跨域

httpSecurity.cors()
	.and()
	.csrf().disable();

cors()允许跨域资源访问。

csrf().disable()禁用跨域安全验证。

认证失败处理类


@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable
{
    private static final long serialVersionUID = -8970718410437077606L;
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
            throws IOException
    {
        int code = HttpStatus.UNAUTHORIZED;
        String msg = StringUtils.fORMat("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
    }
}

到此这篇关于Spring Security实现基于角色的访问控制框架的文章就介绍到这了,更多相关Spring Security访问控制框架内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: SpringSecurity实现基于角色的访问控制框架

本文链接: https://lsjlt.com/news/210890.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • SpringSecurity实现基于角色的访问控制框架
    目录说明Spring Security与Shiro的区别简单使用登录校验流程引入Security设置用户名和密码使用配置类过滤规则授权方式WEB授权方法授权顺序优先级登出跨域认证失败...
    99+
    2023-05-17
    Spring Security访问控制框架 Spring Security访问控制
  • 基于ABP框架实现RBAC(角色访问控制)
    在业务系统需求规划过程中,通常对于诸如组织机构、用户和角色等这种基础功能,通常是将这部分功能规划到通用子域中,这也说明了,对于这部分功能来讲,是系统的基石,整个业务体系是建立于这部分...
    99+
    2024-04-02
  • Spring Security基于注解的接口角色访问控制怎么实现
    本文小编为大家详细介绍“Spring Security基于注解的接口角色访问控制怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Security基于注解的接口角色访问控制怎么实现”文章能帮助大家解决疑惑,下面跟着小编的...
    99+
    2023-06-16
  • kubernetes中如何实现RBAC 角色访问控制
    小编给大家分享一下kubernetes中如何实现RBAC 角色访问控制,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一:RBAC体系结构二:RBAC角色绑定流程三:说明1.RBAC的优势a.对集群中的资源和非资源权限均有完...
    99+
    2023-06-04
  • SpringSecurity实现访问控制url匹配
    目录一、访问控制url匹配1.anyRequest()2.antMatcher()3.regexMatchers()3.1介绍3.2两个参数时使用方式一、访问控制url匹配 在前面讲...
    99+
    2022-11-13
    SpringSecurity 访问控制url匹配 SpringSecurity url匹配
  • Apache如何实现基于IP的访问控制
    Apache可以通过使用mod_authz_host模块来实现基于IP的访问控制。您可以通过编辑Apache的配置文件来配置基于IP的访问控制规则。 以下是一个示例配置,只允许特定IP地址范围内的用户访问您的网站: <Director...
    99+
    2024-07-05
    apache
  • Apache如何实现基于组的访问控制
    Apache可以通过使用基于组的访问控制模块来实现基于组的访问控制。其中,最常用的模块是mod_authz_groupfile模块和mod_authz_dbd模块。 mod_authz_groupfile模块允许管理员使用一个简单的文本文...
    99+
    2024-07-05
    apache
  • 基于角色的权限控制模型RBAC实例分析
    本篇内容主要讲解“基于角色的权限控制模型RBAC实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“基于角色的权限控制模型RBAC实例分析”吧!一、RBAC权限模型简介RBAC权限模型(Rol...
    99+
    2023-06-29
  • Apache如何实现基于用户名的访问控制
    Apache可以通过使用htpasswd文件和.htaccess文件来实现基于用户名的访问控制。 创建htpasswd文件:首先要创建一个包含用户名和密码的htpasswd文件。可以使用htpasswd命令行工具来创建该文件。例如,运行以...
    99+
    2024-07-05
    apache
  • 基于角色的权限控制模型RBAC图文教程
    目录一、RBAC权限模型简介二、RBAC的演化进程2.1.用户与权限直接关联2.2.一个用户拥有一个角色2.3一个用户一个或多个角色三、页面访问权限与操作权限四、数据权限我们开发一个...
    99+
    2024-04-02
  • go语言使用Casbin实现角色的权限控制
    目录介绍 Casbin 是什么?两个核心概念:工作原理:实战初始化数据库用户权限的增删改查总代码封装后的代码参考 本文主要介绍了go语言使用Casbin实现角色的权限控制,分享给大家...
    99+
    2024-04-02
  • Java11 中基于嵌套关系的访问控制优化问题
    目录Java11 之前的实现方式技术债务Java11 中的实现Nestmate 新增的 APIgetNestHostgetNestMembersisNestmateOf后续的改进 你...
    99+
    2024-04-02
  • 在python中实现基于ICE框架的cl
    ICE (Internet Communication Engine) 是zeroc公司实现的通信中间件 几大特性:     1. 多语言支持C++、Java、python, C#等,     2.  对分布式系统的支持,涵盖了负...
    99+
    2023-01-31
    框架 python ICE
  • Java11中基于嵌套关系的访问控制优化详解
    目录前言Java11 之前的实现方式技术债务Java11 中的实现Nestmate 新增的 APIgetNestHostgetNestMembersisNestmateOf后续的改进...
    99+
    2024-04-02
  • Spring Security实现基于RBAC的权限表达式动态访问控制的操作方法
    目录资源权限表达式Spring Security中的实现MethodSecurityExpressionHandler思路以及实现配置和使用昨天有个粉丝加了我,问我如何实现类似shi...
    99+
    2024-04-02
  • Python的Flask框架及Nginx实现静态文件访问限制功能
    Nginx配置 Ngnix,一个高性能的web服务器,毫无疑问它是当下的宠儿。卓越的性能,灵活可扩展,在服务器领域里攻城拔寨,征战天下。 静态文件对于大多数website是不可或缺的一部分。使用Nginx来...
    99+
    2022-06-04
    静态 框架 功能
  • 基于JavaSSM框架实现简易的评教系统
    目录介绍效果图部分核心代码介绍 项目编号:BS-GX-014 数据库:mysql 开发工具:IDEA / ECLIPSE 开发技术:SSM 框架 本系统基于SSM框架实现。主要包含三...
    99+
    2024-04-02
  • Java11中如何解决基于嵌套关系的访问控制优化问题
    这篇文章主要为大家展示了Java11中如何解决基于嵌套关系的访问控制优化问题,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“Java11中如何解决基于嵌套关系的访问控制优化问题”这篇文章吧。Java...
    99+
    2023-06-26
  • Spring boot基于JPA访问MySQL数据库的实现
    本文展示如何通过JPA访问MySQL数据库。 JPA全称Java Persistence API,即Java持久化API,它为Java开发人员提供了一种对象/关系映射工具来管理Jav...
    99+
    2024-04-02
  • 怎么基于JWT实现接口的授权访问
    本篇内容主要讲解“怎么基于JWT实现接口的授权访问”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么基于JWT实现接口的授权访问”吧! 什么是JWTJWT(JSON Web Token...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作