Vue + SpringBoot項目權限及Session管理

權限管理是個很大很複雜的模塊,目前,剛開始做,就化繁爲簡,簡單的切分成前端控件控制,和後端API權限控制。好記性不如爛筆頭,整理一遍思路,慢慢沉澱。

1. 前端控件權限控制

將用戶跟Role掛鉤,admin role, read-only role等等,前端一些增刪改控件以及Admin頁面是否加載的話,可以使用v-if=editAccess, 查詢用戶是否有權限的過程(發get請求到服務端去查)可以放在組件的created hook裏面,有權限則this.editAccess=true,反之false.

2. 後端API權限控制

[ http request 攔截器 springboot 2.x及以後]

後端API控制稍微麻煩些,要聯合登錄以及session過期等一起來做。確保session沒過期,session是合法的,然後才進入到具體的api。對於一些敏感api(例如增刪改api,或者只能admin角色才能做的一些api),幹實事兒之前先進行權限檢查,沒權限的直接response.sendError(...)然後就return結束。

實際上我也考慮過,把增刪改api的權限檢查拿出來,做成一個或者多個攔截器。這麼一來的話,要把api分類,同一個權限級別的api可以放到一個攔截器裏去。Anyway,這是可行的。合適的話,以後往這個方向做。

  1. 在springboot的property文件裏配置上session過期時間(注意:springboot 2.x以前的版本里,這個配置項的名字不一樣的)server.servlet.session.timeout=300s

  2. 用戶登錄成功之後,可以往request.getSession().setAttributes("xxx", "...")塞一些token之類的。同時這個token也保存在服務端的某個數據結構裏。

  3. 做request攔截器,每一個request進來,先進攔截器,攔截器返回true纔可以繼請求api(加了多個攔截器的話,會按照添加順序進到下一個攔截器裏面)。攔截器返回false的話呢,就不會繼續了。
    這個攔截器可以通過繼承HandlerInterceptorAdapter來實現。父類裏有這三個方法:
    preHandle: 執行具體api之前
    postHandle: api執行後
    afterCompletion: 前端收到返回之後
    目前我的需求,只需要override preHandle就好了,如下所示:先驗證session是否過期,然後驗證session是否合法。

public class SessionInterceptor extends HandlerInterceptorAdapter {

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// session expire
		if (request.getSession(false) == null) {
			response.sendError(HttpStatus.SC_UNAUTHORIZED, "Session time out, please re-login");
			return false;
		}
		// validate token in session
		else if (request.getSession().getAttribute(token) != null) {
			if (token is valid) {
				return true;
			} else {
				response.sendError(HttpStatus.SC_UNAUTHORIZED, "Invalid token, please re-login");
				return false;
			}
		}
		// invalid session
		else {
			response.sendError(HttpStatus.SC_UNAUTHORIZED, "Invalid session, please re-login");
			return false;
		}
	}
}
  1. 將定義好的攔截器加入到WebMvcConfigurer裏面去,如下所示。需要注意的是,要先addPathPatterns("…")然後再去添加excludePathPatterns(也就是白名單,這些api的request進來不走攔截器),否則白名單不生效…
@Configuration
public class WebMvcConfig implements WebMvcConfigurer

@Override
    public void addInterceptors(InterceptorRegistry registry) {
    	List<String> excludeUrl = Arrays.asList("/api/login/**","/api/event/insert");
        registry.addInterceptor(new SessionInterceptor()).addPathPatterns("/**")
        .excludePathPatterns(excludeUrl);
    }
  1. 增刪改或者admin api,通過HttpServletRequest和HttpServletResponse進行權限檢查和權限不足時的返回處理
	@PostMapping(value="/editcase",produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public TestCaseInfo editCase(@RequestBody TestCaseInfo caseInfo, HttpServletRequest request, HttpServletResponse response) throws IOException{
		if(user in current session does not have access){
			response.sendError(HttpStatus.SC_FORBIDDEN, "Current user does not have access!");
			return null;
		}
		do what should be done if user has access balabalabala...
	}

[ axios response 攔截器]

前端在收到服務端的返回之後,也可以做一個統一的預處理,判斷一下,如果返回的是401證明Session過期或者不合法,要重新登錄。如果返回的是403證明沒權限等等。具體的HTTP Status Code和它的處理方式,結合code本身的意義以及業務場景來決定,前後端商量好就行。

感覺前端加response攔截器比後端簡單很多啊…

this.$axios.interceptors.response.use(response => {
    return response;
}, err => {
    if (err.response.status === 401) {
      this.$message.error(err.response.statusText + ", please re-login!");
        this.$router.push("/login");        
    } else if (err.response.status === 403) {
        this.$message.error(err.response.statusText + ". User does not have access!");
    } else {
        console.log('err', err.response);
    }
   return Promise.reject(err);
});
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章