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. 註銷刷新令牌
在之前關於處理刷新令牌的文章中,我們已經配置了應用程序能夠通過刷新令牌刷新 Access Token。該實現利用了 Zuul 代理,並使用 CustomPostZuulFilter 將 Authorization Server 接收到的 refresh_token 值添加到 refreshToken Cookie。
當撤銷 Access Token,如前一節所示,與之關聯的 Refresh Token 也會失效。但是,由於我們無法通過 JavaScript 刪除 httpOnly Cookie,因此該 Cookie 將仍然在客户端設置 – 所以我們需要從服務器端刪除它。
讓我們增強 CustomPostZuulFilter 的實現,使其攔截 /oauth/token/revoke URL,以便在遇到該 URL 時刪除 refreshToken Cookie。
@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 認證的應用中註銷用户,並失效該用户的令牌。