環境:SpringBoot2.7.12
在當今的Web應用程序中,權限驗證是一個重要的安全措施,用于確保只有具有適當權限的用戶才能訪問特定的資源。隨著應用程序的規模和復雜性的增加,實現權限驗證變得更加困難。為了解決這個問題,我們可以使用Spring AOP(面向切面編程)和Spring Security的組合,它們可以提供一種有效的方法來實現權限驗證。
在本文中,我們將探討如何使用Spring AOP和Spring Security來實現權限驗證。我們首先介紹Spring AOP和Spring Security的概念,然后解釋如何將它們結合起來實現權限驗證。通過這種方式,我們可以確保只有具有適當權限的用戶能夠訪問受保護的資源,從而提高應用程序的安全性。
Spring AOP是Spring框架中的一個模塊,用于支持面向切面編程。它允許開發者在應用程序中的關鍵點定義切面,從而對程序流程進行干預和控制。通過使用AOP,我們可以將與業務邏輯無關的代碼(如日志記錄、事務管理、權限認證等)抽取出來,并將其放在獨立的切面中,這樣可以提高代碼的可重用性和可維護性。
Spring Security是一個強大的安全框架,用于保護Web應用程序。它提供了豐富的安全特性,包括認證、授權、訪問控制等。通過使用Spring Security,我們可以輕松地實現用戶身份驗證、角色授權、URL級別的訪問控制等功能,從而確保只有經過授權的用戶才能訪問受保護的資源。
我們可以將Spring AOP與Spring Security結合起來實現權限驗證。具體步驟如下:
通過這種方式,我們可以輕松地實現權限驗證,從而提高應用程序的安全性。同時,使用Spring AOP和Spring Security還可以降低代碼的耦合度,提高代碼的可重用性和可維護性。
<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上下文中
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過濾器鏈中
@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接口。
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface PreAuthority { String value() default "" ; }
該切面讀取接口配置的權限,驗證是否具有相應的權限
@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 ; } }
權限驗證工具類
@Componentpublic class AuthorityVerify { public boolean hasAuthority(String authority) { Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities() ; return authorities.contains(new SimpleGrantedAuthority(authority)) ; } }
在上面的切面類中,如果沒有權限是直接拋出的異常,所以這里定義一個全局異常對異常進行統一的處理。都比較簡單,理解即可。
@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..." ; } }
測試用戶
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信息。如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI4ODg4ODgiLCJhdXRob3JpdGllcyI6WyJhcGk6Y3JlYXRlIiwiYXBpOnF1ZXJ5IiwiYXBpOnVwZGF0ZSIsImFwaTpkZWxldGUiXSwiZXhwIjoxNjk5NjE3NTM3fQ.GGLYIP2g5RZZkBoLnyQ_NWOQq_NUQylr5iZH9ouDiCM
圖片
/api/save接口配置的權限是api:save,實際模擬的用戶是沒有這個權限的,所以這里看到的是切面中拋出的異常信息。
圖片
查詢接口正常訪問。
以上是簡單的示例,實際你應該會使用Spring Security結合數據庫一起來驗證管理用戶的。
通過本文的介紹,我們了解了如何使用Spring AOP和Spring Security的組合來實現權限驗證。通過這種方式,我們可以提高應用程序的安全性,并降低代碼的耦合度,提高代碼的可重用性和可維護性。希望本文能夠幫助讀者更好地理解和應用Spring AOP和Spring Security,為他們的應用程序開發提供有益的參考。
在上面的Controller中直接通過@PreAuthority('xxx')進行權限的設置,那我們是不是可以實現類似Spring Security提供@PreAuthorize("hasRole('xxx')")注解的功能,其中hasRole('xxx')是SpEL表達式。其實這里我們可以對切面稍加修改即可實現,部分代碼如下:
初始化SpEL上下文:
@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角色的都可以訪問。
本文鏈接:http://www.www897cc.com/showinfo-26-34646-0.html通過Spring AOP結合SpEL表達式:構建強大且靈活的權限控制體系
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com