当前位置:首页 > 科技  > 软件

通过Spring AOP结合SpEL表达式:构建强大且灵活的权限控制体系

来源: 责编: 时间:2023-11-28 09:36:09 156观看
导读环境:SpringBoot2.7.121.前言在当今的Web应用程序中,权限验证是一个重要的安全措施,用于确保只有具有适当权限的用户才能访问特定的资源。随着应用程序的规模和复杂性的增加,实现权限验证变得更加困难。为了解决这个问题,

环境:SpringBoot2.7.12qEl28资讯网——每日最新资讯28at.com

1.前言

在当今的Web应用程序中,权限验证是一个重要的安全措施,用于确保只有具有适当权限的用户才能访问特定的资源。随着应用程序的规模和复杂性的增加,实现权限验证变得更加困难。为了解决这个问题,我们可以使用Spring AOP(面向切面编程)和Spring Security的组合,它们可以提供一种有效的方法来实现权限验证。qEl28资讯网——每日最新资讯28at.com

在本文中,我们将探讨如何使用Spring AOP和Spring Security来实现权限验证。我们首先介绍Spring AOP和Spring Security的概念,然后解释如何将它们结合起来实现权限验证。通过这种方式,我们可以确保只有具有适当权限的用户能够访问受保护的资源,从而提高应用程序的安全性。qEl28资讯网——每日最新资讯28at.com

一、Spring AOP介绍


Spring AOP是Spring框架中的一个模块,用于支持面向切面编程。它允许开发者在应用程序中的关键点定义切面,从而对程序流程进行干预和控制。通过使用AOP,我们可以将与业务逻辑无关的代码(如日志记录、事务管理、权限认证等)抽取出来,并将其放在独立的切面中,这样可以提高代码的可重用性和可维护性。qEl28资讯网——每日最新资讯28at.com

二、Spring Security介绍


Spring Security是一个强大的安全框架,用于保护Web应用程序。它提供了丰富的安全特性,包括认证、授权、访问控制等。通过使用Spring Security,我们可以轻松地实现用户身份验证、角色授权、URL级别的访问控制等功能,从而确保只有经过授权的用户才能访问受保护的资源。qEl28资讯网——每日最新资讯28at.com

三、Spring AOP与Spring Security的组合


我们可以将Spring AOP与Spring Security结合起来实现权限验证。具体步骤如下:qEl28资讯网——每日最新资讯28at.com

  1. 定义一个Aspect切面,用于实现权限验证逻辑。该Aspect可以拦截用户对受保护资源的访问请求,并验证其权限。
  2. 定义一个Filter,该过滤器实现token的解析,将权限信息保存到当前的安全上下文中,最后添加到Security的过滤器链中。
  3. 在Aspect中,我们可以使用Spring Security提供的API来获取当前用户的身份信息、角色等信息,并根据业务需求判断用户是否具有访问受保护资源的权限。
  4. 如果用户没有足够的权限访问受保护资源,我们可以抛出一个异常,以阻止用户继续访问。
  5. 如果用户具有足够的权限访问受保护资源,我们可以允许用户继续访问该资源。

通过这种方式,我们可以轻松地实现权限验证,从而提高应用程序的安全性。同时,使用Spring AOP和Spring Security还可以降低代码的耦合度,提高代码的可重用性和可维护性。qEl28资讯网——每日最新资讯28at.com

2. 权限认证实现

相关依赖

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-security</artifactId></dependency><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-aop</artifactId></dependency><dependency>    <groupId>com.auth0</groupId>    <artifactId>java-jwt</artifactId>    <version>4.4.0</version></dependency>

权限认证过滤器

该过滤器的作用用来解析token,将权限信息添加到SecurityContext上下文中qEl28资讯网——每日最新资讯28at.com

public class PackAuthenticationFilter extends OncePerRequestFilter {  public static final String TOKEN_NAME = "x-api-token" ;    @SuppressWarnings("unused")  private ApplicationContext context ;    public PackAuthenticationFilter(ApplicationContext context) {    this.context = context ;  }    @Override  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)      throws ServletException, IOException {    String token = request.getHeader(TOKEN_NAME) ;    if (!StringUtils.hasLength(token)) {      response.setContentType("text/html;charset=UTF-8") ;      response.getWriter().println("没有权限访问") ;      return ;    }     // 解析token    List<? extends GrantedAuthority> authorities = JwtUtils.parseAuthority(token) ;    Authentication authentication = new UsernamePasswordAuthenticationToken("", "", authorities) ;    SecurityContextHolder.getContext().setAuthentication(authentication) ;    filterChain.doFilter(request, response) ;  }}

安全配置类

将上面的过滤器添加到Security过滤器链中qEl28资讯网——每日最新资讯28at.com

@Configurationpublic class SecurityConfig {    @Autowired  void setContext(ApplicationContext context) {    this.context = context ;  }  @Bean  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {    http.csrf().disable();    // 对所有的资源全部放行,我们只做对Controller接口的限制访问    http.authorizeRequests().anyRequest().permitAll() ;    // 添加过滤器    http.addFilterBefore(new PackAuthenticationFilter(this.context), UsernamePasswordAuthenticationFilter.class) ;    http.formLogin().disable() ;    return http.build();  }}

自定义注解

该注解的作用用来标注具体的Controller接口。qEl28资讯网——每日最新资讯28at.com

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface PreAuthority {    String value() default "" ;  }

验证切面

该切面读取接口配置的权限,验证是否具有相应的权限qEl28资讯网——每日最新资讯28at.com

@Component@Aspectpublic class AuthenticationAspect {    private AuthorityVerify authorityVerify ;    public AuthenticationAspect(AuthorityVerify authorityVerify) {    this.authorityVerify = authorityVerify ;  }    @Pointcut("@annotation(auth)")  private void authority(PreAuthority auth) {}    @Around("authority(auth)")  public Object test(ProceedingJoinPoint pjp, PreAuthority auth) throws Throwable {    String authority = auth.value() ;    boolean permit = this.authorityVerify.hasAuthority(authority) ;    if (!permit) {      throw new RuntimeException("权限不足") ;    }    Object ret = pjp.proceed() ;    return ret ;  }  }

权限验证工具类qEl28资讯网——每日最新资讯28at.com

@Componentpublic class AuthorityVerify {  public boolean hasAuthority(String authority) {    Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities() ;    return authorities.contains(new SimpleGrantedAuthority(authority)) ;  }  }

全局异常处理

在上面的切面类中,如果没有权限是直接抛出的异常,所以这里定义一个全局异常对异常进行统一的处理。都比较简单,理解即可。
qEl28资讯网——每日最新资讯28at.com

@RestControllerAdvicepublic class GlobalExceptionAdvice {    @ExceptionHandler({Exception.class})  public Object exceptionProcess(Exception e) {    return e.getMessage() ;  }}

测试接口

@RestController@RequestMapping("/api")public class ApiController {  @GetMapping("/save")  @PreAuthority("api:save")  public Object save(HttpServletResponse response) throws Exception {    return "save method invoke..." ;  }    @GetMapping("/{id}")  @PreAuthority("api:query")  public Object query(@PathVariable("id") Integer id) {    return "query method invoke..." ;  }  }

测试用户qEl28资讯网——每日最新资讯28at.com

Map<String, Object> map = new HashMap<>() ;map.put("userId", "888888") ;map.put("authorities", List.of("api:create", "api:query", "api:update", "api:delete")) ;String token = createToken(map) ;System.out.println(token) ;String content = parseToken(token);System.out.println(content) ;System.out.println(">>>>>>>>>>>>>>>>>>>>>") ;System.out.println(parseAuthority(token)) ;

这里模拟了一个用户信息,设置了权限集合,通过这些信息生成JWT信息。如下:qEl28资讯网——每日最新资讯28at.com

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI4ODg4ODgiLCJhdXRob3JpdGllcyI6WyJhcGk6Y3JlYXRlIiwiYXBpOnF1ZXJ5IiwiYXBpOnVwZGF0ZSIsImFwaTpkZWxldGUiXSwiZXhwIjoxNjk5NjE3NTM3fQ.GGLYIP2g5RZZkBoLnyQ_NWOQq_NUQylr5iZH9ouDiCM

测试结果

图片图片qEl28资讯网——每日最新资讯28at.com

/api/save接口配置的权限是api:save,实际模拟的用户是没有这个权限的,所以这里看到的是切面中抛出的异常信息。qEl28资讯网——每日最新资讯28at.com

图片图片qEl28资讯网——每日最新资讯28at.com

查询接口正常访问。qEl28资讯网——每日最新资讯28at.com

以上是简单的示例,实际你应该会使用Spring Security结合数据库一起来验证管理用户的。qEl28资讯网——每日最新资讯28at.com

通过本文的介绍,我们了解了如何使用Spring AOP和Spring Security的组合来实现权限验证。通过这种方式,我们可以提高应用程序的安全性,并降低代码的耦合度,提高代码的可重用性和可维护性。希望本文能够帮助读者更好地理解和应用Spring AOP和Spring Security,为他们的应用程序开发提供有益的参考。qEl28资讯网——每日最新资讯28at.com

思考:

在上面的Controller中直接通过@PreAuthority('xxx')进行权限的设置,那我们是不是可以实现类似Spring Security提供@PreAuthorize("hasRole('xxx')")注解的功能,其中hasRole('xxx')是SpEL表达式。其实这里我们可以对切面稍加修改即可实现,部分代码如下:qEl28资讯网——每日最新资讯28at.com

初始化SpEL上下文:qEl28资讯网——每日最新资讯28at.com

@PostConstructpublic void init() {  SpelParserConfiguration config = new SpelParserConfiguration(true, true);  parser = new SpelExpressionParser(config) ;  context = new StandardEvaluationContext() ;  context.setRootObject(this.authorityVerify) ;}

修改切面

@Around("authority(auth)")public Object test(ProceedingJoinPoint pjp, PreAuthority auth) throws Throwable {  String authority = auth.value() ;  boolean permit = this.parser.parseExpression(authority).getValue(this.context, Boolean.class) ;  if (!permit) {    throw new RuntimeException("不具备对应角色") ;  }  Object ret = pjp.proceed() ;  return ret ;}

修改接口

@GetMapping("/save")@PreAuthority("hasRole({'ADMIN', 'MGR'})")public Object save(HttpServletResponse response) throws Exception {  return "save method invoke..." ;}

该接口只要具有ADMIN或者MGR角色的都可以访问。qEl28资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-34646-0.html通过Spring AOP结合SpEL表达式:构建强大且灵活的权限控制体系

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 阿里面试官:LinkedHashMap是怎么保证元素有序的?

下一篇: 如何使用 Formik 创建 React 表单

标签:
  • 热门焦点
  • 5月iOS设备性能榜:M1 M2依旧是榜单前五

    5月iOS设备性能榜:M1 M2依旧是榜单前五

    和上个月一样,没有新品发布的iOS设备性能榜的上榜设备并没有什么更替,仅仅只有跑分变化而产生的排名变动,刚刚开始的苹果WWDC2023,推出的产品也依旧是新款Mac Pro、新款Mac Stu
  • 帅气纯真少年!日本最帅初中生选美冠军出炉

    帅气纯真少年!日本最帅初中生选美冠军出炉

    日本第一帅哥初一生选美大赛冠军现已正式出炉,冠军是来自千叶县的宗田悠良。日本一直热衷于各种选美大赛,从&ldquo;最美JK&rdquo;起到&ldquo;最美女星&r
  • 学习JavaScript的10个理由...

    学习JavaScript的10个理由...

    作者 | Simplilearn编译 | 王瑞平当你决心学习一门语言的时候,很难选择到底应该学习哪一门,常用的语言有Python、Java、JavaScript、C/CPP、PHP、Swift、C#、Ruby、Objective-
  • 使用LLM插件从命令行访问Llama 2

    使用LLM插件从命令行访问Llama 2

    最近的一个大新闻是Meta AI推出了新的开源授权的大型语言模型Llama 2。这是一项非常重要的进展:Llama 2可免费用于研究和商业用途。(几小时前,swyy发现它已从LLaMA 2更名为Lla
  • 雅柏威士忌多款单品价格大跌,泥煤顶流也不香了?

    雅柏威士忌多款单品价格大跌,泥煤顶流也不香了?

    来源 | 烈酒商业观察编 | 肖海林今年以来,威士忌市场开始出现了降温迹象,越来越多不断暴涨的网红威士忌也开始悄然回归市场理性。近日,LVMH集团旗下苏格兰威士忌品牌雅柏(Ardbeg
  • 猿辅导与新东方的两种“归途”

    猿辅导与新东方的两种“归途”

    作者|卓心月 出品|零态LT(ID:LingTai_LT)如何成为一家伟大企业?答案一定是对&ldquo;势&rdquo;的把握,这其中最关键的当属对企业战略的制定,且能够站在未来看现在,即使这其中的
  • 华为开发者大会2023日程公开:开设鸿蒙HarmonyOS 4体验区

    华为开发者大会2023日程公开:开设鸿蒙HarmonyOS 4体验区

    IT之家 7 月 31 日消息,华为今日公布了 HDC.Together 开发者大会 2023 的详细日程。整场大会将于 8 月 4 日-6 日之间举行,届时将发布最新一代鸿蒙 H
  • 2纳米决战2025

    2纳米决战2025

    集微网报道 从三强争霸到四雄逐鹿,2nm的厮杀声已然隐约传来。无论是老牌劲旅台积电、三星,还是誓言重回先进制程领先地位的英特尔,甚至初成立不久的新
  • 回归OPPO两年,一加赢了销量,输了品牌

    回归OPPO两年,一加赢了销量,输了品牌

    成为OPPO旗下主打性能的先锋品牌后,一加屡创佳绩。今年618期间,一加手机全渠道销量同比增长362%,凭借一加 11、一加 Ace 2、一加 Ace 2V三款爆品,一加
Top
Baidu
map