在Java EE項目中,權限控制是經(jīng)常遇到的問題。尤其是在多角色的系統(tǒng)中,權限控制的粒度更細,也更為重要。
問題描述
系統(tǒng)中有三種角色,教師,管理員,學生,角色權限部分交叉。如果將權限控制的邏輯添加到每一個接口,代碼冗雜且不易擴展,維護。我們將權限控制部分單獨分離出來,并使用非侵入式的方法為每一個接口添加權限。
解決方案
- 注解:利用Java的注解機制,在運行時得到接口的權限信息。
- AOP:Spring MVC提供了攔截器功能,本質(zhì)上是AOP。通過攔截器在處理請求前統(tǒng)一檢驗權限,在不改變業(yè)務代碼的基礎上添加了權限控制。
實現(xiàn)
學生權限:StudentPermission
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface StudentPermission {}
還定義了教師權限(TeacherPermission)、管理員權限(AdminPermission)、自身權限(SelfPermission)。這里只定義空注解,起標記作用。
添加攔截器:PermissionsInterceptor
public class PermissionsInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
boolean isPass=true;
if(method.getAnnotation(TeacherPermission.class)!=null){
isPass=isTeacher(request);
}
if(method.getAnnotation(StudentPermission.class)!=null){
isPass=isStudent(request);
}
if(method.getAnnotation(AdminPermission.class)!=null){
isPass=isAdmin(request);
}
if(method.getAnnotation(SelfPermission.class)!=null){
isPass=isSelf(request);
}
if(!isPass){//未授權,返回401信息
Gson gson=new Gson();
ResponseJson json=new ResponseJson();
json.setCode(UNAUTHORIZED.getCode());
json.setMessage(UNAUTHORIZED.getMessage());
response.setCharacterEncoding("UTF-8");
response.getWriter().write(gson.toJson(json));
}
return isPass;
}
private boolean isTeacher(HttpServletRequest request){
//判斷是否是老師
}
private boolean isStudent(HttpServletRequest request){
//判斷是否是學生
}
private boolean isAdmin(HttpServletRequest request){
//判斷是否是管理員
}
private boolean isSelf(HttpServletRequest request){
//判斷是否是自身
}
}
配置攔截器
<mvc:interceptors>
</mvc:interceptor>
<!-- 權限攔截器 -->
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="cqupt.nmid.foreign.interceptor.PermissionsInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
注解接口
在需要權限控制的接口添加注釋
@TeacherPermission
@RequestMapping(value="/students/{id}",method=RequestMethod.GET)
@ResponseBody
public ResponseJson getStudentsInfo(@PathVariable(value="id") int studentId) {
return studentService.getStudentsInfo(studentId);
}
總結(jié)
使用注解和攔截器可以很輕松的實現(xiàn)權限控制,這里只是寫個例子,只適合簡單的權限控制,但是流程已經(jīng)制定好,可以很簡單的進行擴展。如果權限的驗證機制比較復雜,例如App接口的token加密驗證,單獨實現(xiàn)一個權限模塊再利用攔截器進行請求分發(fā)可能是更好的方式。