Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Spring Security---授权操作详解

Spring Security---授权操作详解

作者头像
大忽悠爱学习
发布于 2021-12-07 10:56:41
发布于 2021-12-07 10:56:41
95900
代码可运行
举报
文章被收录于专栏:c++与qt学习c++与qt学习
运行总次数:0
代码可运行

Spring Security---授权操作详解


1.授权

所谓的授权,就是用户如果要访问某一个资源,我们要去检查用户是否具备这样的权限,如果具备就允许访问,如果不具备,则不允许访问。

2.准备测试用户

因为我们现在还没有连接数据库,所以测试用户还是基于内存来配置。

基于内存配置测试用户,我们有两种方式,第一种就是前面几篇文章用的配置方式,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("dhy")
            .password("123").roles("admin")
            .and()
            .withUser("大忽悠")
            .password("123")
            .roles("user");
}

这是一种配置方式。

由于 Spring Security 支持多种数据源,例如内存、数据库、LDAP 等,这些不同来源的数据被共同封装成了一个 UserDetailService 接口,任何实现了该接口的对象都可以作为认证数据源。

因此我们还可以通过重写 WebSecurityConfigurerAdapter 中的 userDetailsService 方法来提供一个 UserDetailService 实例进而配置多个用户:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   @Bean
   protected UserDetailsService userDetailsService() {
      InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
      manager.createUser(User.withUsername("dhy").password("123").roles("admin").build());
      manager.createUser(User.withUsername("大忽悠").password("123").roles("user").build());
      return manager;
   }

放入容器中后,会被自动使用

两种基于内存定义用户的方法,大家任选一个。


3.准备测试接口

测试用户准备好了,接下来我们准备三个测试接口。如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

    @GetMapping("/admin/hello")
    public String admin() {
        return "admin";
    }

    @GetMapping("/user/hello")
    public String user() {
        return "user";
    }
}

这三个测试接口,我们的规划是这样的:

  • /hello 是任何人都可以访问的接口
  • /admin/hello 是具有 admin 身份的人才能访问的接口
  • /user/hello 是具有 user 身份的人才能访问的接口
  • 所有 user 能够访问的资源,admin 都能够访问

注意第四条规范意味着所有具备 admin 身份的人自动具备 user 身份。


4.配置

接下来我们来配置权限的拦截规则,在 Spring Security 的 configure(HttpSecurity http) 方法中,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
http.authorizeRequests()
        .antMatchers("/admin/**").hasRole("admin")
        .antMatchers("/user/**").hasRole("user")
        .anyRequest().authenticated()
        .and()
        ...
        ...

这里的匹配规则我们采用了 Ant 风格的路径匹配符,Ant 风格的路径匹配符在 Spring 家族中使用非常广泛,它的匹配规则也非常简单:

通配符

含义

**

匹配多层路径

*

匹配单层路径

?

匹配任意单个字符

上面配置的含义是:

  • 如果请求路径满足 /admin/** 格式,则用户需要具备 admin 角色。
  • 如果请求路径满足 /user/** 格式,则用户需要具备 user 角色。
  • 剩余的其他格式的请求路径,只需要认证(登录)后就可以访问。

注意代码中配置的三条规则的顺序非常重要,和 Shiro 类似,Spring Security 在匹配的时候也是按照从上往下的顺序来匹配,一旦匹配到了就不继续匹配了,所以拦截规则的顺序不能写错。

另一方面,如果你强制将 anyRequest 配置在 antMatchers 前面,像下面这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
http.authorizeRequests()
        .anyRequest().authenticated()
        .antMatchers("/admin/**").hasRole("admin")
        .antMatchers("/user/**").hasRole("user")
        .and()

此时项目在启动的时候,就会报错,会提示不能在 anyRequest 之后添加 antMatchers

这从语义上很好理解,anyRequest 已经包含了其他请求了,在它之后如果还配置其他请求也没有任何意义。

从语义上理解,anyRequest 应该放在最后,表示除了前面拦截规则之外,剩下的请求要如何处理。

在拦截规则的配置类 AbstractRequestMatcherRegistry 中,我们可以看到如下一些代码(部分源码):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract class AbstractRequestMatcherRegistry<C> {
	private boolean anyRequestConfigured = false;
	public C anyRequest() {
		Assert.state(!this.anyRequestConfigured, "Can't configure anyRequest after itself");
		this.anyRequestConfigured = true;
		return configurer;
	}
	public C antMatchers(HttpMethod method, String... antPatterns) {
		Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
		return chainRequestMatchers(RequestMatchers.antMatchers(method, antPatterns));
	}
	public C antMatchers(String... antPatterns) {
		Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
		return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
	}
	protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method,
			String... mvcPatterns) {
		Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
		return matchers;
	}
	public C regexMatchers(HttpMethod method, String... regexPatterns) {
		Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
		return chainRequestMatchers(RequestMatchers.regexMatchers(method, regexPatterns));
	}
	public C regexMatchers(String... regexPatterns) {
		Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
		return chainRequestMatchers(RequestMatchers.regexMatchers(regexPatterns));
	}
	public C requestMatchers(RequestMatcher... requestMatchers) {
		Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
		return chainRequestMatchers(Arrays.asList(requestMatchers));
	}
}

从这段源码中,我们可以看到,在任何拦截规则之前(包括 anyRequest 自身),都会先判断 anyRequest 是否已经配置,如果已经配置,则会抛出异常,系统启动失败。

这样大家就理解了为什么 anyRequest 一定要放在最后。


5.启动测试

接下来,我们启动项目进行测试。

我们先通过大忽悠用户的账号访问:

登录成功后,分别访问 /hello,/admin/hello 以及 /user/hello 三个接口,其中:

  • /hello 因为登录后就可以访问,这个接口访问成功。
  • /admin/hello 需要 admin 身份,所以访问失败。
  • /user/hello 需要 user 身份,所以访问成功。

首先登录:

访问admin身份可以访问的资源时,成功

当访问user身份才可以访问的资源时,会显示403,无权限


完整的配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   private ObjectMapper objectMapper=new ObjectMapper();

   @Bean
   PasswordEncoder passwordEncoder() {
      return NoOpPasswordEncoder.getInstance();
   }

   @Override
   public void configure(WebSecurity web) throws Exception {
      web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
   }

   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.inMemoryAuthentication()
              .withUser("dhy")
              .password("123").roles("admin")
              .and()
              .withUser("大忽悠")
              .password("123")
              .roles("user");
   }

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
              .antMatchers("/admin/**").hasRole("admin")
              .antMatchers("/user/**").hasRole("user")
              .anyRequest().authenticated()
              .and()
              .formLogin()
              //注意放行请求,否则会404
              .loginPage("/login.html").permitAll()
              .loginProcessingUrl("/login").permitAll()
              .successHandler(new AuthenticationSuccessHandler() {
                 @Override
                 public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                    httpServletResponse.setContentType("application/json;charset=UTF-8");
                    httpServletResponse.getWriter().write(objectMapper.writeValueAsString(authentication));
                 }
              }).permitAll()
              .and()
              .csrf().disable();

   }
}

角色继承

所有 user 能够访问的资源,admin 都能够访问,很明显我们目前的代码还不具备这样的功能。

要实现所有 user 能够访问的资源,admin 都能够访问,这涉及到另外一个知识点,叫做角色继承。

这在实际开发中非常有用。

上级可能具备下级的所有权限,如果使用角色继承,这个功能就很好实现,我们只需要在 SecurityConfig 中添加如下代码来配置角色继承关系即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Bean
RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
    hierarchy.setHierarchy("ROLE_admin > ROLE_user");
    return hierarchy;
}

注意,在配置时,需要给角色手动加上 ROLE_ 前缀。上面的配置表示 ROLE_admin 自动具备 ROLE_user 的权限。

配置完成后,重启项目,此时我们发现 dhy 也能访问 /user/hello 这个接口了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/11/18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring Security 中的授权操作原来这么简单
http://mpvideo.qpic.cn/0bf2oaaawaaaiaac6y4lorpfa4gdbnyaacya.f10002.mp4?dis_k=c5c02b2ff8bb260049e37b7
江南一点雨
2020/04/10
2.6K0
Spring Security 中的授权操作原来这么简单
Spring Security用户认证和授权(二)
授权是指确定用户是否有权访问某些资源或执行某些操作的过程。Spring Security提供了多种授权方式,例如基于角色的授权、基于表达式的授权等。
堕落飞鸟
2023/04/15
4610
Spring Security---退出功能详解
其实使用Spring Security进行logout非常简单,只需要在spring Security配置类配置项上加上这样一行代码:http.logout()。关于spring Security配置类的其他很多实现、如:HttpBasic模式、formLogin模式、自定义登录验证结果、使用权限表达式、session会话管理,。本节的核心内容就是在原有配置的基础上,加上这样一行代码:http.logout()。
大忽悠爱学习
2021/12/07
2.2K0
Spring Security---退出功能详解
Spring Security---将用户数据存入数据库详解
Spring Security 支持多种不同的数据源,这些不同的数据源最终都将被封装成 UserDetailsService 的实例
大忽悠爱学习
2021/12/07
6720
Spring Security---将用户数据存入数据库详解
让Spring Security 来保护你的Spring Boot项目吧
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
100000860378
2018/09/13
1.2K0
让Spring Security 来保护你的Spring Boot项目吧
Spring Boot 安全框架 Spring Security 入门
基本上,在所有的开发的系统中,都必须做认证(authentication)和授权(authorization),以保证系统的安全性。考虑到很多胖友对认证和授权有点分不清楚,在这里引用一个网上有趣的例子
用户8351972
2023/02/27
9640
Spring Boot 3 集成 Spring Security(2)授权
在《Spring Boot 3 集成 Spring Security(1)》中,我们简单实现了 Spring Security 的认证功能,通过实现用户身份验证来确保系统的安全性。Spring Security的重要核心功能功能是“认证”和“授权”。接下来我们将深入了解授权机制,看如何控制用户在系统中可以访问的资源和操作。在 Spring Security 中,授权主要基于角色和权限的概念进行控制。
Harry技术
2025/01/11
1210
Spring Boot 3 集成 Spring Security(2)授权
使用 Spring Security 进行基本的 HTTP 认证和授权(二)
HTTP 授权是一种基于 HTTP 协议的授权机制,用于限制用户对资源的访问权限。HTTP 授权使用 HTTP 协议中的 Authorization 头来传递用户凭据和授权信息。
堕落飞鸟
2023/04/15
5540
Spring Security--短信验证码详解
在这一步我们需要写一个controller接收用户的获取验证码请求。注意:一定要为“/smscode”访问路径配置为permitAll访问权限,因为spring security默认拦截所有路径,除了默认配置的/login请求,只有经过登录认证过后的请求才会默认可以访问。
大忽悠爱学习
2021/12/07
1.6K0
Spring Security--短信验证码详解
Spring Security 中如何让上级拥有下级的所有权限?
松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程
江南一点雨
2020/09/14
1.4K0
Spring Boot的安全配置(二)
OAuth 2.0是一种授权协议,允许用户授权第三方应用程序访问他们的资源。在Spring Boot中,可以使用spring-security-oauth2-autoconfigure库来实现OAuth 2.0身份验证。该库提供了一些可用的OAuth 2.0身份验证客户端,包括Facebook、GitHub、Google和Twitter等。
堕落飞鸟
2023/04/05
1K0
Spring Security学习(二)
被LogoutFilter在成功注销后调用,用来进行重定向或者转发相应的目的地。注意这个接口与LogoutHandler几乎一样,但是可以抛出异常。
allsmallpig
2021/02/25
8470
Spring Boot + Security-01基于内存认证
代码地址:https://github.com/zhangpu1211/Spring-Security-Demos
听城
2020/02/24
7680
Spring Security(三)--核心配置解读
上一篇文章《Spring Security(二)--Guides》,通过Spring Security的配置项了解了Spring Security是如何保护我们的应用的,本篇文章对上一次的配置做一个分析。 目录 核心配置解读 3.1 功能介绍 3.2 EnableWebSecurity WebSecurityConfiguration AuthenticationConfiguration 3.3 WebSecurityConfigurerAdapter HttpSecurity常用配置 WebSecuri
kirito-moe
2018/04/27
9860
Spring Security(三)--核心配置解读
Spring Security (三) 核心配置解读
上一篇文章《Spring Security(二)--Guides》,通过Spring Security的配置项了解了Spring Security是如何保护我们的应用的,本篇文章对上一次的配置做一个分析。 3 核心配置解读 3.1 功能介绍 这是Spring Security入门指南中的配置项: @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
程序猿DD
2018/02/01
1.9K0
Spring Security (三) 核心配置解读
Spring Boot的安全配置(一)
Spring Boot是一个非常流行的Java开发框架,提供了各种实用的功能和组件来快速构建应用程序。安全是任何Web应用程序开发的关键方面,因为它涉及到用户的身份验证和授权。Spring Boot提供了一些安全功能来保护Web应用程序免受恶意攻击,包括身份验证、授权、加密、防止跨站脚本攻击(XSS)和跨站请求伪造(CSRF)等。
堕落飞鸟
2023/04/05
1.2K0
Spring Security安全
如果添加了Spring Security的依赖,那么web应用默认对所有的HTTP路径(也称为终点,端点,表示API的具体网址)使用’basic’认证。为了给web应用添加方法级别(method-level)的保护,可以添加@EnableGlobalMethodSecurity并使用想要的设置。
关忆北.
2020/10/15
7730
Spring Security认证和授权(二)
假设在/admin/test/下的内容是系统后台管理相关的 API,在/web/test下的内容是面向客户端公开访 问的API,在/user/test/下的内容是用户操作自身数据相关的API;显然,/admin/test必须拥有管理员权限才能进行操作,而/user/test必须在用户登录后才能进行操作。
Java技术债务
2022/08/09
5780
Spring Security认证和授权(二)
Java一分钟之-Spring Security:身份验证与授权
Spring Security是Java中广泛使用的安全框架,它提供了强大的身份验证和授权功能。本文将深入浅出地介绍Spring Security的常见问题、易错点及其解决方案,并附上代码示例。
Jimaks
2024/06/08
2240
Spring Security 中的 hasRole 和 hasAuthority 有区别吗?
----我相信很多小伙伴在初次接触 Spring Security 时,一定会被这个问题所困扰,例如如下两段配置:
江南一点雨
2020/09/23
16.6K1
相关推荐
Spring Security 中的授权操作原来这么简单
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档