当前位置:首页 > 技术分析 > 正文内容

Spring Security权限控制系列(二)

ruisui882个月前 (04-30)技术分析13

环境:Springboot2.4.12 + Spring Security 5.4.9


本篇主要内容:请求拦截及自定义登录页面

上一篇:《Spring Security权限控制系列(一)

自定义拦截请求

默认项目中引入Spring Security后会拦截所有的请求,这其中包括了静态资源,这肯定不是我们希望的,接下来我们看如何进行资源自定义的拦截。

  • 新建如下静态资源
  • 配置静态资源访问路径

由于静态资源默认访问路径是/**,这里为了区分静态资源与Controller给静态资源加一个前缀。

spring:
  mvc:
    static-path-pattern: /resources/**
  • 访问静态资源

先将Spring Security从项目中移除,然后进行访问。分别访问index.js和index.html

都能正常访问,接下来将Spring Security加到项目中后,再进行访问会发现之前还能访问的现在直接跳转到了登录页面

  • 静态资源放行

自定义配置设置路径方向规则

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests() // 获取基于SpEL表达式的基于URL的授权对象
      .antMatchers("/resources/**") // 设定URI路径规则以/resoures开头的任意请求
      .permitAll() ; // 只要是基于上面/resources开头的请求都进行放行
    http.formLogin() ; // 如果请求不是上面配置的访问uri前缀则进行登录
  }
}

再次访问静态资源,这时候就能正常访问了,没有跳转到登录页面,在访问Controller接口 GET /demos/home运行结果

发现静态资源能访问,同时我们的Controller也能访问

  • 修改配置只放行指定的资源
protected void configure(HttpSecurity http) throws Exception {
  http
    .authorizeRequests()
    .antMatchers("/resources/**")
    .permitAll() ; // 方向/resource请求的资源   ①
  http
    .authorizeRequests()
    .anyRequest() // 任意请求
    .authenticated() ; // 必须进行登录认证授权 ② 
  http.formLogin() ;
}

以上配置后以/resources前缀的请求都会方向,其它任意的请求都会进行拦截跳转到登录页面。

注意:上面的 ① ② 如果顺序进行颠倒后服务启动会报错。报错信息如下

Caused by: java.lang.IllegalStateException: Can't configure antMatchers after anyRequest
	at org.springframework.util.Assert.state(Assert.java:76) ~[spring-core-5.3.12.jar:5.3.12]

不能在anyRequest之后配置antMatchers。

  • 为请求配置角色

定义2个Controller

@RestController
@RequestMapping("/demos")
public class DemoController {
  @GetMapping("home")
  public Object home() {
    return "demos home" ;
  }
}
@RestController
@RequestMapping("/api")
public class ApiController {
  @GetMapping("/{id}")
  public Object get(@PathVariable("id") Integer id) {
    return "获取 - " + id + " - 数据" ;
  }
}

我们期望/demos/**接口访问必须拥有USERS权限,/api/**接口访问必须拥有ADMIN权限, 配置如下:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  // 配置guest用户,该用户拥有ADMIN角色
  auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("guest").password("123456").roles("ADMIN") ;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
  http.csrf().disable() ;
  http.authorizeRequests().antMatchers("/resources/**").permitAll() ;
  // 这里无需使用ROLE_前缀,系统会自动插入该前缀
  http.authorizeRequests().antMatchers("/demos/**").hasRole("USERS") ; // /demos/**必须具备USERS角色
  http.authorizeRequests().antMatchers("/api/**").hasRole("ADMIN") ; // /api/**必须具备ADMIN角色
  http.authorizeRequests().anyRequest().authenticated() ;
  http.formLogin() ;
}

分别访问/demos/home 和 /api/1接口

通过guest/123456登录后,该接口之间返回了403的状态错误(读取403.html)

/api/**接口访问正常,接下来我们在配置一个用于USERS权限的用户

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.inMemoryAuthentication()
    .passwordEncoder(NoOpPasswordEncoder.getInstance())
    .withUser("guest").password("123456").roles("ADMIN")
    .and()
    .withUser("test").password("666666").roles("USERS") ;
}

通过test用户访问/demos/home接口登录后能正常访问。

  • 配置多权限

在很多情况下我们期望只要用户用于任意其中一个权限就认定可以访问该资源,如何配置?

http.authorizeRequests().antMatchers("/demos/**").hasAnyRole("USERS", "AKKF", "BLLE") ;
http.authorizeRequests().antMatchers("/api/**").hasAnyRole("ADMIN", "MGR", "SYSTEM") ;

通过上面的配置即可满足只要拥有任意一个权限就可以放行。

  • 其它配置

多个URI具有相同的权限

http.authorizeRequests().antMatchers("/demos/**", "/api/**").hasAnyAuthority("ROLE_USERS", "ROLE_ADMIN") ;

对请求的Method控制

http.authorizeRequests().antMatchers(HttpMethod.GET).permitAll() ;

自定义登录页面

  • 引入依赖
<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  • thymeleaf配置
spring:
  thymeleaf:
    prefix: classpath:/templates/ 
  • 登录页面

在/resources/templates/下新建login.html页面

这里省去无关紧要的东西

<div class="loginContainer">
  <div class="pageTitle">
    <h3>认证登录</h3>
  </div>
  <div class="loginPanel">
    <div class="loginTitle">安全登录</div>
      <div class="loginContent">
        <form method="post" action="login">
          <div class="c-row">
            <label>安全帐号</label>
            <input type="text" class="input-control" id="username" name="username" placeholder="帐号">
          </div>
          <div class="c-row">
            <label>安全密码</label>
            <input type="password" class="input-control" id="password" name="password" placeholder="密码">
          </div>
          <div class="c-row" style="height: auto;">
            <input type="checkbox" class="checkbox-control" id="remember-me" name="remember-me"/><label for="remember-me">记住我</label>
          </div>
          <div class="c-row" style="margin-top: 20px;">
            <button type="submit" class="btn btn-sm btn-primary" style="padding: 10px 15px;width: 60%;border-radius: 20px;">安全登录</button>
          </div>
        </form>
        <div class="c-row">
          <div th:if="${param.error}" th:text="${session.SPRING_SECURITY_LAST_EXCEPTION?.message }" class="alert alert-danger" style="padding:5px; margin-bottom:5px;"></div>
        </div>		
      </div>
    </div>
</div>
  • Controller定义login页面
@Controller
public class LoginController {
  @GetMapping("/custom/login")
  public String login() {
    return "login" ;
  }
}
  • 自定义配置登录页
protected void configure(HttpSecurity http) throws Exception {
  http.csrf().disable() ;
  http.authorizeRequests().antMatchers("/resources/**").permitAll() ;
  http.authorizeRequests().antMatchers("/demos/**").hasRole("USERS") ;
  http.authorizeRequests().antMatchers("/api/**").hasRole("ADMIN") ;
  // 登录页面指向上面配置的Controller即可
  http.formLogin().loginPage("/custom/login") ;
}

测试

总结

  1. Spring Security如何配置拦截请求
  2. 资源访问必须具备权限的配置
  3. 自定义登录页面

到此本篇内容结束。下一篇将介绍:

  1. 自定义异常处理

一文带你彻底理解Spring WebFlux的工作原理
Spring MVC高级知识点自定义请求匹配路径
Spring WebFlux请求处理流程
Spring AOP实现原理源码详细分析
Spring Cloud Gateway应用详解1之谓词
Spring AOP切入点类型及系统提供的非常常用的切入点
Spring中自定义数据类型转换详解
Spring 引介增强IntroductionAdvisor使用

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/3691.html

分享给朋友:

“Spring Security权限控制系列(二)” 的相关文章

深度解析!AI智能体在To B领域应用,汽车售后服务落地全攻略

在汽车售后服务领域,AI智能体的应用正带来一场效率和专业度的革命。本文深度解析了一个AI智能体在To B领域的实际应用案例,介绍了AI智能体如何通过提升服务顾问和维修技师的专业度及维修效率,优化汽车售后服务流程。上周我分享了AI智能体+AI小程序To C的AI应用场景《1000%增长!我仅用一个小时...

学前端,这30个CSS选择器,你必须熟记

你学会了基本的id,class类选择器和descendant后代选择器,然后就觉得完事了吗?如果这样,你就会错过许多灵活运用CSS的机会。虽然本文提到的许多选择器都属于CSS3,并且只能在现代的浏览器中使用,但学会这些是大有好处的。什么是CSS选择器呢?每一条css样式定义由两部分组成,形式如下:[...

vue2中路由的使用步骤,你学会了吗?

今天我们来整理下关于vue2中路由的使用步骤:1. 导入 vue 文件和Vue-router文件(注意:vue-router是依赖vue运行的,所以一定在vue后引入vue-router)2. 定义路由组件模板3. 创建路由实例并定义路由规则4. 将路由实例挂载给Vue实例5. 在结构区域定义控制路...

vue.js 双向绑定如何理解,有什么好处!#云南小程序开发

Vue.js 的双向数据绑定是借助于 JavaScript 的一些特性,如对象的属性 getter 和 setter 以及 Vue 的依赖追踪系统实现的。简单来说,双向数据绑定就是数据与视图间的双向通信,也就是说数据的改变会马上反映到视图中,视图的改变也会立刻改变数据。具体来说,当你改变了数据时,视...

嵌入式实操——基于RT1170 使能SEMC配置SDRAM功能(八)

本文主要是通过迁移的思维,记录本人初次使用NXP MCUXpresso SDK API进行BSP开发MCUXpresso SDK SEMC API 接口链接  在MCUXpresso SDK 框架下提供了对SEMC DDR进行操作的接口。学习链接:https://community.nxp.com/...

跨域问题的4种解决方案

前言难以置信,我居然被跨域问题折磨了一上午。相信很多程序员都遇到过跨域问题,当然,解决方案也有很多种。但我今天尝试了无数种办法,依旧没有解决。直到最后我媳妇儿给了我个提示,会不会跨域问题只是表象,真正的bug在其他地方。后来,经过我仔细排查,终于发现原来是PhalApi框架中的一个小问题,引发了跨域...