当前位置: 首页 > ai >正文

Spring Security授权管理

授权是Spring Security的核心功能之一,是根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则可正常访问,没有访问的权限时则会被拒绝访问。认证是为了保证用户身份的合法性,而授权则是为了更细粒度地对隐私数据进行划分,授权是在认证通过后发生的,以控制不同的用户访问不同的资源。Spring Security提供了授权方法,开发者通过这些方法进行用户访问控制.

Spring Security授权流程

实现授权需要对用户的访问进行拦截校验,校验用户的权限是否可以操作指定的资源。Spring Security使用标准Filter建立了对Web请求的拦截,最终实现对资源的授权访问。

①拦截请求。已认证用户访问受保护的Web资源将被SecurityFilterChain中FilterSecurityInterceptor实例对象拦截。

②获取资源访问策略。FilterSecurityInterceptor实例对象会通过SecurityMetadataSource的子类DefaultFilterInvocationSecurityMetadataSource实例对象中获取要访问当前资源所需要的权限,权限封装在Collection实例对象中。 SecurityMetadataSource是读取访问策略的抽象,具体读取的内容,就是开发者配置的访问规则。

③FilterSecurityInterceptor通过AccessDecisionManager进行授权决策,若决策通过,则允许访问资 源,否则将禁止访问。AccessDecisionManager中包含一系列AccessDecisionVoter,可对当前认证过的身份是否有权访问对应的资源进行投票,AccessDecisionManager根据投票结果做出最终决策。

Spring Security自定义授权

根据授权的位置和形式,通常可以将授权的方式分为Web授权和方法授权,这两种授权方式都会调用AccessDecisionManager进行授权决策。下面分别对这两种自定义授权的方式进行讲解。

1.Web授权

Spring Security的底层实现本质是通过多个Filter形成的过滤器链完成,过滤器链中提供了默认的安全拦截机制,设置安全拦截规则,以控制用户的访问。HttpSecurity是SecurityBuilder接口的实现类,是HTTP安全相关的构建器,Spring Security中可以通过HttpSecurity对象设置安全拦截规则,并通过该对象构建过滤器链。

HttpSecurity可以根据不同的业务场景,对不同的URL采用不同的权限处理策略。当开发者需要配置项目的安全拦截规则时,可以调用HttpSecurity对象对应的方法实现。

HttpSecurity类的常用方法

方法

作用

authorizeRequests()

开启基于HttpServletRequest请求访问的限制

formLogin()

开启基于表单的用户登录

httpBasic()

开启基于HTTP请求的Basic认证登录

logout()

开启退出登录的支持

sessionManagement()

开启Session管理配置

rememberMe()

开启记住我功能

csrf()

配置CSRF跨站请求伪造防护功能

通过authorizeRequests()方法可以添加用户请求控制的规则,这些规则通过用户请求控制的相关方法指定。 

用户请求控制的常用方法

方法

作用

antMatchers(String... antPatterns)

开启Ant风格的路径匹配

mvcMatchers(String... patterns)

开启MVC风格的路径匹配,与Ant风格类似

regexMatchers(String... regexPatterns)

开启正则表达式的路径匹配

and()

功能连接符

anyRequest()

匹配任何请求

rememberMe()

开启记住我功能

access(String attribute)

使用基于SpEL表达式的角色进行匹配

方法

作用

hasAnyRole(String... roles)

匹配用户是否有参数中的任意角色

hasRole(String role)

匹配用户是否有某一个角色

hasAnyAuthority(String... authorities)

匹配用户是否有参数中的任意权限

hasAuthority(String authority)

匹配用户是否有某一个权限

authenticated()

匹配已经登录认证的用户

fullyAuthenticated()

匹配完整登录认证的用户(非rememberMe登录用户)

hasIpAddress(String ipaddressExpression)

匹配某IP地址的访问请求

permitAll()

无条件对请求进行放行

通过HttpSecurity类的formLogin()方法开启基于表单的用户登录后,可以指定表单认证的相关设置。

基于表单的身份验证的常见方法

方法

作用

loginPage(String loginPage)

指定自定义登录界面,不使用SpringSecurity默认登录界面

loginProcessingUrl(String loginProcessingUrl)

指定处理登录的请求url,为表单提交用户信息的Action

successForwardUrl(String forwardUrl) 

指定登录成功后默认跳转的路径

下面通过案例演示在Spring Boot项目中使用Spring Security的Web授权方式进行权限管理。

(1)导入登录页面

在项目的resources目录的templates文件夹中导入自定义的登录页面login.html。

<html lang="en" xmlns:th="http://www.thymeleaf.org"><head><title>图书管理系统</title><link rel="stylesheet" type="text/css" th:href="@{/css/webbase.css}"><link rel="stylesheet" type="text/css" th:href="@{/css/pages-login-manage.css}"></head><body><div class="loginmanage"><div class="py-container"><h4 class="manage-title">图书管理系统</h4><div class="loginform"><ul class="sui-nav nav-tabs tab-wraped"><li class="active"><h3>账户登录</h3></li></ul><div class="tab-content tab-wraped"><div id="profile" class="tab-pane active"><form id="loginform" class="sui-form" th:action="@{/doLogin}" method="post"><div class="input-prepend"><span class="add-on loginname">用户名</span><input type="text" placeholder="用户名" class="span2 input-xfat" name="username"></div><div class="input-prepend"><span class="add-on loginpwd">密码</span><input type="password" placeholder="请输入密码" class="span2 input-xfat" name="password"></div><div class="logined"><a class="sui-btn btn-block btn-xlarge btn-danger"href='javascript:document:loginform.submit();' target="_self">登&nbsp;&nbsp;录</a></div></form></div></div></div></div></div></body></html>

(2)编辑配置类

在项目的WebSecurityConfig配置类中使用HttpSecurity对象设置安全拦截规则,并创建SecurityFilterChain对象交由Spring管理

@Configuration
public  class  WebSecurityConfig {
@Bean
public  PasswordEncoder passwordEncoder() {
return  new  BCryptPasswordEncoder();
}
@Bean
public  SecurityFilterChain securityFilterChain(HttpSecurity http) throws  Exception{
http.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.mvcMatchers("/loginview","/css/**","/img/**").permitAll()
.mvcMatchers("/book/admin/**").hasRole("ADMIN")
.anyRequest().authenticated() // 任何请求,登录后可以访问
.and()
.formLogin()
.loginPage("/loginview")
.loginProcessingUrl("/doLogin")
.and()
.csrf().disable()//禁止csrf 跨站请求保护;
.headers().frameOptions().sameOrigin();
return  http.build();
}
}

在WebMvcConfig配置类中添加loginview的视图映射

@Configuration
public  class  WebMvcConfig implements  WebMvcConfigurer {
@Override
public  void  addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("main");
registry.addViewController("/loginview").setViewName("login");
}
}

(3)测试效果

启动项目,在浏览器中通过“http://localhost:8080/”访问项目首页。

在登录页面使用zhangsan的用户信息进行登录。

图书管理需要角色为ROLE_ADMIN的用户才可以访问,用户zhangsan的角色为ROLE_COMMON,在后台首页单击“图书管理”链接。

使用用户lisi进行登录,lisi对应的角色为ROLE_ADMIN,登录成功再次访问“图书管理”。

2.方法授权

Spring Security除了可以在配置类中通过创建过滤器链设置安全拦截规则外,还可以使用@Secured、@RolesAllowed和@PreAuthorize注解控制类中所有方法或者单独某个方法的访问权限,以实现对访问进行授权管理。

使用@Secured和@RolesAllowed注解时,只需在注解中指定访问当前注解标注的类或方法所需要具有的角色,允许多个角色访问时,使用大括号对角色信息进行包裹,角色信息之间使用分号分隔即可。

@RequestMapping("list")
@Secured({"ROLE_ADMIN","ROLE_COMMON"})
public String findList() {return "book_list";
}
@RequestMapping("admin/manag")
@RolesAllowed("ROLE_ADMIN")
public String findManagList() {return "book_manag";
}

 @PreAuthorize注解会在方法执行前进行权限验证,支持SpEL表达式。

@RequestMapping("list")
@PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_COMMON')")
public String findList() {return "book_list";
}
@RequestMapping("admin/manag")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String findManagList() {return "book_manag";
}

@Secured、@RolesAllowed和@PreAuthorize注解都可以对方法的访问进行权限控制。 @Secured为Spring Security提供的注解。

@RolesAllowed为基于JSR 250规范的注解。

@PreAuthorize支持SpEL表达式。

Spring Security默认是禁用方法级别的安全控制注解,要想使用注解进行方法授权,可以使用@EnableGlobalMethodSecurity注解开启基于方法的安全认证机制,该注解可以标注在任意配置类上。

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,jsr250Enabled = true,prePostEnabled = true)
public class WebSecurityConfig  {……}

(1)开启基于方法的安全认证机制 在项目的WebSecurityConfig配置类中开启基于方法的安全认证机制,并将类中HttpSecurity对象设置的访问“图书管理”拦截规则删除,以确保对资源授权地为方法授权,修改后的代码如下所示。

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true ,prePostEnabled = true )
public  class  WebSecurityConfig {
@Bean
public  PasswordEncoder passwordEncoder() {
return  new  BCryptPasswordEncoder();
}
@Bean
public  SecurityFilterChain securityFilterChain(HttpSecurity http) throws  Exception {
http.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.mvcMatchers("/loginview","/css/**","/img/**").permitAll()
.anyRequest().authenticated() // 任何请求,登录后才可以访问
.and()
.formLogin()
.loginPage("/loginview")
.loginProcessingUrl("/doLogin")
.permitAll()
.and()
.csrf().disable()//禁止csrf 跨站请求保护;
.headers().frameOptions().sameOrigin();
return  http.build();
}
}

(2)方法授权

在BookController类的findManagList()方法上使用注解指定访问该方法所需的角色

@Controller
@RequestMapping("book")public  class  BookController {
@RequestMapping("list")
public  String findList() {
return  "book_list";
}
@RequestMapping("admin/manag")
@Secured("ROLE_ADMIN")
public  String findManagList() {
return  "book_manag";
}
}

(3)测试效果

启动项目,在浏览器中通过“http://localhost:8080/”访问项目首页后,使用用户zhangsan登录系统。

单击左侧的“图书管理”链接。

在用户登录页面使用用户lisi进行登录,登录成功后再次访问“图书管理”。

动态展示菜单

掌握动态展示菜单,能够通过Spring Security的授权管理实现动态展示菜单。

在前面的讲解中,只是通过Spring Security对后台资源的访问根据角色进行权限控制,前端页面并没有做任何处理,不同角色能看到的前端页面是一样的,即使当前用户没有对应的访问权限,依然能看到对应的菜单,用户体验较差。下面在前面案例的基础上,讲解如何使用Spring Security与Thymeleaf整合实现前端页面根据登录用户的角色动态展示菜单。 

1.添加依赖

添加Thymeleaf与Spring Security 5的集成包:thymeleaf-extras-springsecurity5

<dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>

2.修改页面代码

打开后台首页main.html,引入Spring Security安全标签,并在页面中根据需求使用Spring Security标签指定为不同角色显示不同的页面内容,实现动态展示控制

<html xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/extras/spring-security"><head><meta charset="utf-8"><title>网上图书馆</title><headers><frame-options policy="SAMEORIGIN" /></headers><link rel="stylesheet" th:href="@{/css/bootstrap.css}"><link rel="stylesheet" th:href="@{/css/AdminLTE.css}"><link rel="stylesheet" th:href="@{/css/_all-skins.min.css}"><script th:src="@{/js/jquery.min.js}"></script><script th:src="@{/js/bootstrap.js}"></script><script type="text/javascript">function SetIFrameHeight() {var iframeid = document.getElementById("iframe");if (document.getElementById) {/*设置 内容展示区的高度等于页面可视区的高度*/iframeid.height = document.documentElement.clientHeight;}}</script></head><body class="hold-transition skin-green sidebar-mini"><div class="wrapper"><!-- 页面头部 --><header class="main-header"><!-- Logo --><a th:href="@{/}" class="logo"><span class="logo-lg"><b>网上图书馆</b></span></a><!-- 头部导航 --><nav class="navbar navbar-static-top"><div class="navbar-custom-menu"><ul class="nav navbar-nav"><li class="dropdown user user-menu"><a th:if="${session.user !=null}"><img th:src="@{/img/user.jpg}" class="user-image"alt="User Image"><span class="hidden-xs" th:text="${session.user.name}"></span>
</a></li><li class="dropdown user user-menu"><a><span class="hidden-xs">注销</span></a></li></ul></div></nav></header><!-- 页面头部 /--><!-- 导航侧栏 --><aside class="main-sidebar"><section class="sidebar"><ul class="sidebar-menu"><li sec:authorize="hasAnyAuthority('ROLE_COMMON','ROLE_ADMIN')"><a th:href="@{/book/list}" target="iframe"><i class="fa fa-circle-o"></i>图书阅读</a></li><li sec:authorize="hasAuthority('ROLE_ADMIN')"><a th:href="@{/book/admin/manag}" target="iframe"><i class="fa fa-circle-o"></i>图书管理</a></li></ul></section><!-- /.sidebar --></aside><!-- 导航侧栏 /--><!-- 内容展示区域 --><div class="content-wrapper"><iframe width="100%" id="iframe" name="iframe" onload="SetIFrameHeight()"frameborder="0" ></iframe></div></div></body></html>

3.效果测试

重启项目。

使用用户zhangsan的信息进行登录,登录后展示后台首页。

使用用户lisi的信息进行登录,登录后展示后台首页。

http://www.xdnf.cn/news/2659.html

相关文章:

  • 综合练习一
  • JAVA基础:Collections 工具类实战指南-从排序到线程安全
  • ViTa-Zero:零样本视觉触觉目标 6D 姿态估计
  • Ubuntu深度学习革命:NVIDIA-Docker终极指南与创新实践
  • LLVIP、KAIST、M3FD数据集
  • GD32F407单片机开发入门(十六)单片机IAP(在应用编程)详解及实战源码
  • 消息队列优化指南:处理堆积与保障消息可靠性
  • 喜马拉雅卖身腾讯音乐:在线音频独立时代的终结
  • Molex莫仕连接器:增强高级驾驶辅助系统,打造更安全的汽车
  • codeforces C. The Trail
  • 【Nginx】 使用least_conn负载均衡算法是否能将客户端的长连接分散到不同的服务器上demo
  • 【AI生产力工具】Windsurf,一款AI编程工具
  • 华纳云:centos如何实现JSP页面的动态加载
  • 模板方法模式(Template Method Pattern)
  • 数据库对象概述
  • Java项目与技术栈场景题深度解析
  • C语言(5)—操作符详解
  • leetcode 143. 重排链表
  • js day8
  • Java学习手册: IoC 容器与依赖注入
  • leetcode刷题日记——两数相加
  • 【Redis】基础4:作为分布式锁
  • 搭建speak yarn集群:从零开始的详细指南
  • 关于健身房管理系统前后端软件开发主要功能需求分析
  • 深入理解网络原理:TCP协议详解
  • MCP Servers玩玩WebUI自动化
  • 如何在idea 中写spark程序
  • UARA串口开发基础
  • Dify+DeepSeek实战教程!企业级 AI 文档库本地化部署,数据安全与智能检索我都要
  • OpenResty技术深度解析:原理、应用与生态对比-优雅草卓伊凡