一、前言
本篇文章将講述Spring Security 動态配置設定url權限,未登入權限控制,登入過後根據登入使用者角色授予通路url權限
基本環境
- spring-boot 2.1.8
- mybatis-plus 2.2.0
- mysql 資料庫
- maven項目
Spring Security入門學習可參考之前文章:
- SpringBoot內建Spring Security入門體驗(一)
- Spring Security 自定義登入認證(二)
二、資料庫建表
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SN0Y2NzQTNzYDM1YGMzMzMmRWNxUmYzEmYxUGM3ETM38CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
表關系簡介:
- 使用者表t_sys_user 關聯 角色表t_sys_role 兩者建立中間關系表t_sys_user_role
- 角色表t_sys_role 關聯 權限表t_sys_permission 兩者建立中間關系表t_sys_role_permission
- 最終展現效果為目前登入使用者所具備的角色關聯能通路的所有url,隻要給角色配置設定相應的url權限即可
溫馨小提示:這裡邏輯根據個人業務來定義,小編這裡講解案例隻給使用者對應的角色配置設定通路權限,像其它的 直接給使用者配置設定權限等等可以自己實作
表模拟資料如下:
三、Spring Security 動态權限控制
1、未登入通路權限控制
自定義AdminAuthenticationEntryPoint類實作AuthenticationEntryPoint類
這裡是認證權限入口 -> 即在未登入的情況下通路所有接口都會攔截到此(除了放行忽略接口)
溫馨小提示:ResponseUtils和ApiResult是小編這裡模拟前後端分離情況下傳回json格式資料所使用工具類,具體實作可參考文末給出的demo源碼
@Componentpublic class AdminAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) { ResponseUtils.out(response, ApiResult.fail("未登入!!!")); }}
2、自定義過濾器MyAuthenticationFilter繼承OncePerRequestFilter實作通路鑒權
每次通路接口都會經過此,我們可以在這裡記錄請求參數、響應内容,或者處理前後端分離情況下,以token換使用者權限資訊,token是否過期,請求頭類型是否正确,防止非法請求等等
- logRequestBody()方法:記錄請求消息體
- logResponseBody()方法:記錄響應消息體
【注:請求的HttpServletRequest流隻能讀一次,下一次就不能讀取了,是以這裡要使用自定義的MultiReadHttpServletRequest工具解決流隻能讀一次的問題,響應同理,具體可參考文末demo源碼實作】
@[email protected] class MyAuthenticationFilter extends OncePerRequestFilter { private final UserDetailsServiceImpl userDetailsService; protected MyAuthenticationFilter(UserDetailsServiceImpl userDetailsService) { this.userDetailsService = userDetailsService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { System.out.println("請求頭類型: " + request.getContentType()); if ((request.getContentType() == null && request.getContentLength() > 0) || (request.getContentType() != null && !request.getContentType().contains(Constants.REQUEST_HEADERS_CONTENT_TYPE))) { filterChain.doFilter(request, response); return; } MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request); MultiReadHttpServletResponse wrappedResponse = new MultiReadHttpServletResponse(response); StopWatch stopWatch = new StopWatch(); try { stopWatch.start(); // 記錄請求的消息體 logRequestBody(wrappedRequest);// String token = "123"; // 前後端分離情況下,前端登入後将token儲存在cookie中,每次通路接口時通過token去拿使用者權限 String token = wrappedRequest.getHeader(Constants.REQUEST_HEADER); log.debug("背景檢查令牌:{}