1. 概述
在本快速教程中,我們將演示如何向 OAuth Spring Security 應用程序添加註銷功能。
我們當然會使用在先前文章中描述的 OAuth 應用程序——使用 OAuth2 創建 REST API。
注意:本文使用 Spring OAuth 遺留項目。對於使用新版 Spring Security 5 堆棧的版本,請查看我們的文章“在 OAuth 安全應用程序中註銷”。
2. 取消訪問令牌
簡單來説,在 OAuth 安全環境中註銷涉及 使用户的訪問令牌失效——以便它無法再被使用。在 JdbcTokenStore 類型的實現中,這意味着從 TokenStore 中移除令牌。
讓我們實現一個刪除令牌的操作。我們將在這裏使用主 URL 結構 /oauth/token,並簡單地引入一個新的 DELETE 操作。
現在,由於我們實際上在這裏使用 /oauth/token URI——我們需要小心處理它。我們無法簡單地將其添加到任何控制器——因為框架已經將操作映射到該 URI——使用 POST 和 GET。
相反,我們需要定義它為一個 @FrameworkEndpoint,以便它會被拾取並由 FrameworkEndpointHandlerMapping 解決,而不是標準 RequestMappingHandlerMapping。這樣我們就不再遇到部分匹配,也不再有衝突:
@FrameworkEndpoint
public class RevokeTokenEndpoint {
@Resource(name = "tokenServices")
ConsumerTokenServices tokenServices;
@RequestMapping(method = RequestMethod.DELETE, value = "/oauth/token")
@ResponseBody
public void revokeToken(HttpServletRequest request) {
String authorization = request.getHeader("Authorization");
if (authorization != null && authorization.contains("Bearer")){
String tokenId = authorization.substring("Bearer".length()+1);
tokenServices.revokeToken(tokenId);
}
}
}
請注意,我們從請求中提取令牌,僅使用標準的 Authorization 頭部。
3. 移除刷新令牌
在之前關於處理刷新令牌的文章中,我們已經配置了應用程序能夠通過刷新令牌刷新訪問令牌。這種實現方式使用了 Zuul 代理 – 藉助 CustomPostZuulFilter 將從授權服務器接收到的 refresh_token 值添加到 refreshToken 餅乾中。
當撤銷訪問令牌,如前一節所示,與之關聯的刷新令牌也將失效。但是,由於我們無法通過 JavaScript 刪除 httpOnly 餅乾 – 因此我們需要從服務器端刪除它。
讓我們增強 CustomPostZuulFilter 的實現,以便它攔截 /oauth/token/revoke URL,從而在遇到該 URL 時刪除 refreshToken 餅乾:
@Component
public class CustomPostZuulFilter extends ZuulFilter {
//...
@Override
public Object run() {
//...
String requestMethod = ctx.getRequest().getMethod();
if (requestURI.contains("oauth/token") && requestMethod.equals("DELETE")) {
Cookie cookie = new Cookie("refreshToken", "");
cookie.setMaxAge(0);
cookie.setPath(ctx.getRequest().getContextPath() + "/oauth/token");
ctx.getResponse().addCookie(cookie);
}
//...
}
}
4. 從 AngularJS 客户端移除訪問令牌
除了從令牌存儲中撤銷訪問令牌之外,還需要從客户端移除 access_token 餅乾。讓我們為我們的 AngularJS 控制器添加一個清除 access_token 餅乾並調用 /oauth/token/revoke DELETE 映射的方法:
$scope.logout = function() {
logout($scope.loginData);
}
function logout(params) {
var req = {
method: 'DELETE',
url: "oauth/token"
}
$http(req).then(
function(data){
$cookies.remove("access_token");
window.location.href="login";
},function(){
console.log("error");
}
);
}
此函數將在點擊 註銷 鏈接時調用:
<a class="btn btn-info" href="#" ng-click="logout()">Logout</a>
5. 結論
在本快速但深入的教程中,我們展示瞭如何從一個使用 OAuth 保護的應用程序中註銷用户並失效該用户的令牌。