Spring Security OAuth2 token權限隔離實例解析
這篇文章主要介紹了Spring Security OAuth2 token權限隔離實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
由于項目OAuth2采用了多種模式,授權碼模式為第三方系統(tǒng)接入,密碼模式用于用戶登錄,Client模式用于服務間調(diào)用,
所有不同的模式下的token需要用 @PreAuthorize("hasAuthority('client')") 進行隔離,遇到問題一直驗證不通過。
通過調(diào)試發(fā)現(xiàn)資源服務從授權服務拿到的authrities字段一直為空, StackOverFlow說低版本(項目中才2.0.15)的OAuth2實現(xiàn)權限隔離需要 重寫UserInfoTokenService
但是資源服務太多所以考慮重寫授權服務的返回值,如何重寫?在哪里重寫?是下面要介紹的~
一、哪里重寫?
資源服務器向授權服務服務器獲取資源時候,返回的user信息重寫,加入authorities
@RestController @Slf4j public class UserController { @Autowired HttpServletRequest request; @GetMapping("/user") public Principal user(Principal principal) { log.info("獲取user信息:{}", JSON.toJSON(principal)); return principal; }
返回的具體用戶信息:
{ "principal": { "password": "$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa", "phone": "13918438965", "credentialsNonExpired": true, "accountNonExpired": true, "enabled": true, "accountNonLocked": true, "username": "4738195728608789333" }, "authenticated": true, "oAuth2Request": { "redirectUri": "http://www.baidu.com", "responseTypes": ["code"], "approved": true, "extensions": {}, "clientId": "external", "scope": ["auth_base"], "requestParameters": { "code": "ovzMSk", "grant_type": "authorization_code", "scope": "auth_base", "response_type": "code", "redirect_uri": "http://www.baidu.com", "state": "123", "client_secret": "D524C1A0811DA49592F841085CC0063EB62B3001252A9454", "client_id": "external" }, "refresh": false, "grantType": "authorization_code", "authorities": [{ "authority": "auth_base" }], "resourceIds": [] }, "clientOnly": false, "credentials": "", "name": "4738195728608789333", "userAuthentication": { "principal": { "password": "$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa", "phone": "13918438965", "credentialsNonExpired": true, "accountNonExpired": true, "enabled": true, "accountNonLocked": true, "username": "4738195728608789333" }, "authenticated": true, "oAuth2Request": { "responseTypes": [], "approved": true, "extensions": {}, "clientId": "gt", "scope": ["frontend"], "requestParameters": { "auth_type": "sms", "device_id": "5c5d1d7b-50ae-4347-9aee-7a7686055f4d", "grant_type": "password", "client_id": "gt", "username": "13918438965" }, "refresh": false, "grantType": "password", "authorities": [{ "authority": "client" }], "resourceIds": [] }, "clientOnly": false, "credentials": "", "name": "4738195728608789333", "userAuthentication": { "principal": { "password": "$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa", "phone": "13918438965", "credentialsNonExpired": true, "accountNonExpired": true, "enabled": true, "accountNonLocked": true, "username": "4738195728608789333" }, "authenticated": true, "name": "4738195728608789333", "details": { "auth_type": "sms", "device_id": "5c5d1d7b-50ae-4347-9aee-7a7686055f4d", "grant_type": "password", "client_secret": "D524C1A0811DA49592F841085CC0063EB62B3001252A94542795D1CA9824A941", "client_id": "gt", "username": "13918438965" }, "authorities": [] }, "details": { "tokenType": "Bearer", "tokenValue": "f7870e71-7b0f-4a4a-9c6f-bb6d1f903ad9", "remoteAddress": "0:0:0:0:0:0:0:1" }, "authorities": [] }, "details": { "tokenType": "Bearer", "tokenValue": "7829005c-5ebe-4428-b951-89477b24316e", "remoteAddress": "0:0:0:0:0:0:0:1" }, "authorities": [] }
二、如何重寫?
principal是OAuth2Authentication實例,OAuth2Authentication主要包括OAuth2Request storedRequest、Authentication userAuthentication,
重寫目的是將storedRequest authorities復制到authoritie中,但問題是authoritie不讓修改的,沒辦法只能重寫這個OAuth2Authentication了。
為了改變authoritie重寫:
@GetMapping("/user") public Principal user(Principal principal) { log.info("獲取user信息:{}", JSON.toJSON(principal)); OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) principal; OAuth2Request storedRequest = oAuth2Authentication.getOAuth2Request(); Authentication userAuthentication = oAuth2Authentication.getUserAuthentication(); // 為了服務端進行token權限隔離 定制OAuth2Authentication CustomOAuth2Authentication customOAuth2Authentication = new CustomOAuth2Authentication(storedRequest, userAuthentication, storedRequest.getAuthorities()); customOAuth2Authentication.setDetails(oAuth2Authentication.getDetails()); log.info("返回用戶信息:{}", JSON.toJSON(customOAuth2Authentication)); return customOAuth2Authentication; }
CustomOAuth2Authentication :
package com.brightcns.wuxi.citizencard.auth.domain; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.CredentialsContainer; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.provider.OAuth2Request; import java.util.Collection; /** * @author maxianming * @date 2018/10/29 13:53 */ public class CustomOAuth2Authentication extends AbstractAuthenticationToken { private static final long serialVersionUID = -4809832298438307309L; private final OAuth2Request storedRequest; private final Authentication userAuthentication; /** * Construct an OAuth 2 authentication. Since some grant types don't require user authentication, the user * authentication may be null. * @param storedRequest The authorization request (must not be null). * @param userAuthentication The user authentication (possibly null). */ public CustomOAuth2Authentication(OAuth2Request storedRequest, Authentication userAuthentication, Collection<? extends GrantedAuthority> authorities) { /** * 為了服務端進行token權限隔離 {@link @PreAuthorize("hasAuthority('server')")},自定義OAuth2Authentication使得支持改變authorities */ super(authorities != null ? authorities : userAuthentication == null ? storedRequest.getAuthorities() : userAuthentication.getAuthorities()); this.storedRequest = storedRequest; this.userAuthentication = userAuthentication; } public Object getCredentials() { return ""; } public Object getPrincipal() { return this.userAuthentication == null ? this.storedRequest.getClientId() : this.userAuthentication .getPrincipal(); } /** * Convenience method to check if there is a user associated with this token, or just a client application. * * @return true if this token represents a client app not acting on behalf of a user */ public boolean isClientOnly() { return userAuthentication == null; } /** * The authorization request containing details of the client application. * * @return The client authentication. */ public OAuth2Request getOAuth2Request() { return storedRequest; } /** * The user authentication. * * @return The user authentication. */ public Authentication getUserAuthentication() { return userAuthentication; } @Override public boolean isAuthenticated() { return this.storedRequest.isApproved() && (this.userAuthentication == null || this.userAuthentication.isAuthenticated()); } @Override public void eraseCredentials() { super.eraseCredentials(); if (this.userAuthentication != null && CredentialsContainer.class.isAssignableFrom(this.userAuthentication.getClass())) { CredentialsContainer.class.cast(this.userAuthentication).eraseCredentials(); } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof CustomOAuth2Authentication)) { return false; } if (!super.equals(o)) { return false; } CustomOAuth2Authentication that = (CustomOAuth2Authentication) o; if (!storedRequest.equals(that.storedRequest)) { return false; } if (userAuthentication != null ? !userAuthentication.equals(that.userAuthentication) : that.userAuthentication != null) { return false; } if (getDetails() != null ? !getDetails().equals(that.getDetails()) : that.getDetails() != null) { // return false; } return true; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + storedRequest.hashCode(); result = 31 * result + (userAuthentication != null ? userAuthentication.hashCode() : 0); return result; } }
主要在OAuth2Authentication基礎上修改了30-35行代碼
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
java Map轉(zhuǎn)Object與Object轉(zhuǎn)Map實現(xiàn)代碼
這篇文章主要介紹了 java Map轉(zhuǎn)Object與Object轉(zhuǎn)Map實現(xiàn)代碼的相關資料,需要的朋友可以參考下2017-02-02SpringBoot3.0+SpringSecurity6.0+JWT的實現(xiàn)
本文主要介紹了SpringBoot3.0+SpringSecurity6.0+JWT的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-11-11JVM入門之類加載與字節(jié)碼技術(類加載與類的加載器)
Java字節(jié)碼增強指的是在Java字節(jié)碼生成之后,對其進行修改,增強其功能,這種方式相當于對應用程序的二進制文件進行修改。Java字節(jié)碼增強主要是為了減少冗余代碼,提高性能等2021-06-06