上一篇我們簡單的分析了一下認證流程,通過程序的啟動加載了各類的配置信息。接下來我們一起來看一下授權流程,爭取完成和前面簡單的web基於sessin的認證方式一致。由於在授權過程中,我們預先會給用於設置角色,關於如果加載配置的角色信息這里就不做介紹了,上一篇的加載過程中我們可以發現相關的信息。
本篇依舊基於spring-security-basic
1|0配置角色信息
配置用戶及其角色信息的方式很多,我們這次依舊采取配置文件的方式,不用代碼或其他的配置方式,在之前的配置用戶信息的地方application.yml,添加用戶的角色信息。
這樣我們就完成了最簡單的用戶角色賦予。在加載用戶信息時我們知道會生成一個User對象,將其用戶名、密碼、權限信息封裝進去。
這里需要注意一下關於role信息的加載
也就是說我們上方配置的ADMIN,USER會被轉化成ROLE_ADMIN,ROLE_USER
2|01、獲取用戶信息
我們在BasicController
類中添加一個獲取認證用戶信息的接口
我們從session中去獲取用戶的信息,然后拿到其授權信息就可以做相應的判斷了request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
這一段代碼我們找到是在HttpSessionSecurityContextRepository.saveContext(SecurityContext context)
中放入的,SPRING_SECURITY_CONTEXT
是其維護的常量,這樣我們就有可以根據這個key去獲取當前的會話信息了。
當然我們還有另外的獲取用戶信息的方式還記得我們在AbstractAuthenticationProcessingFilter
這個核心過濾器中的successfulAuthentication
方法
這里將其認證成功的結果信息放入到上下文中 SecurityContextHolder.getContext().setAuthentication(authResult);
那我們也是可以直接通過其get
方法獲取SecurityContextHolder.getContext();
登陸后直接訪問接口localhost:8080/getUser
可以看到,控制台打印的三段信息是完全一樣的。說明這里通過三種方式獲取的用戶信息是一致的。既然可以獲取到當前登錄的用戶信息,接下來我們就可以通過用戶信息的判斷來決定其是否可以訪問那些接口。
3|02、自定義攔截器
上一步我們通過三種方式獲取到了認證用戶的信息,這里我們將設計一個攔截器來控制用戶的訪問權限。我們先設計兩個接口,一個只能admin角色用戶才可以訪問,一個只能user角色用戶才可以訪問
我們設計了兩個接口,通過url來區別不同角色訪問的結果,我們再設計一個攔截器,這里我們可以直接參考前面的文章 基於session的認證方式 中定義的攔截器
同時生效該攔截器
4|03、注解方式判斷
通過攔截器的方式配置,看上去非常的繁瑣,如果我需要給某個接口添加一個角色訪問權限,還需要去修改攔截器中的判斷邏輯。當然Spring Security也提供了非常方便的注解模式去控制接口,需要修改哪個接口的角色訪問,直接在接口上修改就可以了
非常的簡單,一個注解就幫我們解決了攔截器中完成的事情,其實他們的原理是差不多的。不過這里有幾個需要關注的點
-
@PreAuthorize注解的生效,需要提前開啟的。需要在@EnableGlobalMethodSecurity(prePostEnabled = true) 注解中生效,因為PreAuthorize 默認是false
-
@PreAuthorize是支持表達式方式進行設置的,我用的是hasRole。是其內置的表達式庫SecurityExpressionRoot中的方法
-
hasRole最終調用的是hasAnyAuthorityName的方法,這里會有一個缺省的前綴,當前你也可以寫成hasRole('ROLE_ADMIN')的。並且是變長數組,我們還可一進行多角色的判斷例如:hasRole('ROLE','USER')
到這里,我們已經完成了基於攔截器和注解方式的接口授權設置,基本上都是在零配置的基礎上完成的。我們寫發現了,好像不太容易擴展信息,例如application.yml中沒辦法同時設置多個用戶,認證成功后我想跳轉到自定義的頁面或者自定義的信息。別急,從下一篇開始,我們將逐步對代碼進行改造,一步一步打造成你想滿足的各種需求