因爲項目OAuth2採用了多種模式,受權碼模式爲第三方系統接入,密碼模式用於用戶登陸,Client模式用於服務間調用,java
全部不一樣的模式下的token須要用 @PreAuthorize("hasAuthority('client')") 進行隔離,遇到問題一直驗證不經過。spring
經過調試發現資源服務從受權服務拿到的authrities字段一直爲空, StackOverFlow說低版本(項目中才2.0.15)的OAuth2實現權限隔離須要 重寫UserInfoTokenService服務器
可是資源服務太多因此考慮重寫受權服務的返回值,如何重寫?在哪裏重寫?是下面要介紹的~app
1、哪裏重寫?frontend
資源服務器向受權服務服務器獲取資源時候,返回的user信息重寫,加入authoritiesdom
@RestController @Slf4j public class UserController { @Autowired HttpServletRequest request; @GetMapping("/user") public Principal user(Principal principal) { log.info("獲取user信息:{}", JSON.toJSON(principal));
return principal;
}
返回的具體用戶信息:ide
1 { 2 "principal": { 3 "password": "$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa", 4 "phone": "13918438965", 5 "credentialsNonExpired": true, 6 "accountNonExpired": true, 7 "enabled": true, 8 "accountNonLocked": true, 9 "username": "4738195728608789333" 10 }, 11 "authenticated": true, 12 "oAuth2Request": { 13 "redirectUri": "http://www.baidu.com", 14 "responseTypes": ["code"], 15 "approved": true, 16 "extensions": {}, 17 "clientId": "external", 18 "scope": ["auth_base"], 19 "requestParameters": { 20 "code": "ovzMSk", 21 "grant_type": "authorization_code", 22 "scope": "auth_base", 23 "response_type": "code", 24 "redirect_uri": "http://www.baidu.com", 25 "state": "123", 26 "client_secret": "D524C1A0811DA49592F841085CC0063EB62B3001252A9454", 27 "client_id": "external" 28 }, 29 "refresh": false, 30 "grantType": "authorization_code", 31 "authorities": [{ 32 "authority": "auth_base" 33 }], 34 "resourceIds": [] 35 }, 36 "clientOnly": false, 37 "credentials": "", 38 "name": "4738195728608789333", 39 "userAuthentication": { 40 "principal": { 41 "password": "$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa", 42 "phone": "13918438965", 43 "credentialsNonExpired": true, 44 "accountNonExpired": true, 45 "enabled": true, 46 "accountNonLocked": true, 47 "username": "4738195728608789333" 48 }, 49 "authenticated": true, 50 "oAuth2Request": { 51 "responseTypes": [], 52 "approved": true, 53 "extensions": {}, 54 "clientId": "gt", 55 "scope": ["frontend"], 56 "requestParameters": { 57 "auth_type": "sms", 58 "device_id": "5c5d1d7b-50ae-4347-9aee-7a7686055f4d", 59 "grant_type": "password", 60 "client_id": "gt", 61 "username": "13918438965" 62 }, 63 "refresh": false, 64 "grantType": "password", 65 "authorities": [{ 66 "authority": "client" 67 }], 68 "resourceIds": [] 69 }, 70 "clientOnly": false, 71 "credentials": "", 72 "name": "4738195728608789333", 73 "userAuthentication": { 74 "principal": { 75 "password": "$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa", 76 "phone": "13918438965", 77 "credentialsNonExpired": true, 78 "accountNonExpired": true, 79 "enabled": true, 80 "accountNonLocked": true, 81 "username": "4738195728608789333" 82 }, 83 "authenticated": true, 84 "name": "4738195728608789333", 85 "details": { 86 "auth_type": "sms", 87 "device_id": "5c5d1d7b-50ae-4347-9aee-7a7686055f4d", 88 "grant_type": "password", 89 "client_secret": "D524C1A0811DA49592F841085CC0063EB62B3001252A94542795D1CA9824A941", 90 "client_id": "gt", 91 "username": "13918438965" 92 }, 93 "authorities": [] 94 }, 95 "details": { 96 "tokenType": "Bearer", 97 "tokenValue": "f7870e71-7b0f-4a4a-9c6f-bb6d1f903ad9", 98 "remoteAddress": "0:0:0:0:0:0:0:1" 99 }, 100 "authorities": [] 101 }, 102 "details": { 103 "tokenType": "Bearer", 104 "tokenValue": "7829005c-5ebe-4428-b951-89477b24316e", 105 "remoteAddress": "0:0:0:0:0:0:0:1" 106 }, 107 "authorities": [] 108 }
2、如何重寫?ui
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 :this
1 package com.brightcns.wuxi.citizencard.auth.domain; 2 3 import org.springframework.security.authentication.AbstractAuthenticationToken; 4 import org.springframework.security.core.Authentication; 5 import org.springframework.security.core.CredentialsContainer; 6 import org.springframework.security.core.GrantedAuthority; 7 import org.springframework.security.oauth2.provider.OAuth2Request; 8 9 import java.util.Collection; 10 11 /** 12 * @author maxianming 13 * @date 2018/10/29 13:53 14 */ 15 public class CustomOAuth2Authentication extends AbstractAuthenticationToken { 16 17 private static final long serialVersionUID = -4809832298438307309L; 18 19 private final OAuth2Request storedRequest; 20 21 private final Authentication userAuthentication; 22 23 /** 24 * Construct an OAuth 2 authentication. Since some grant types don't require user authentication, the user 25 * authentication may be null. 26 * @param storedRequest The authorization request (must not be null). 27 * @param userAuthentication The user authentication (possibly null). 28 */ 29 public CustomOAuth2Authentication(OAuth2Request storedRequest, Authentication userAuthentication, Collection<? extends GrantedAuthority> authorities) { 30 /** 31 * 爲了服務端進行token權限隔離 {@link @PreAuthorize("hasAuthority('server')")},自定義OAuth2Authentication使得支持改變authorities 32 */ 33 super(authorities != null ? authorities : userAuthentication == null ? storedRequest.getAuthorities() : userAuthentication.getAuthorities()); 34 this.storedRequest = storedRequest; 35 this.userAuthentication = userAuthentication; 36 } 37 38 public Object getCredentials() { 39 return ""; 40 } 41 42 public Object getPrincipal() { 43 return this.userAuthentication == null ? this.storedRequest.getClientId() : this.userAuthentication 44 .getPrincipal(); 45 } 46 47 /** 48 * Convenience method to check if there is a user associated with this token, or just a client application. 49 * 50 * @return true if this token represents a client app not acting on behalf of a user 51 */ 52 public boolean isClientOnly() { 53 return userAuthentication == null; 54 } 55 56 /** 57 * The authorization request containing details of the client application. 58 * 59 * @return The client authentication. 60 */ 61 public OAuth2Request getOAuth2Request() { 62 return storedRequest; 63 } 64 65 /** 66 * The user authentication. 67 * 68 * @return The user authentication. 69 */ 70 public Authentication getUserAuthentication() { 71 return userAuthentication; 72 } 73 74 @Override 75 public boolean isAuthenticated() { 76 return this.storedRequest.isApproved() 77 && (this.userAuthentication == null || this.userAuthentication.isAuthenticated()); 78 } 79 80 @Override 81 public void eraseCredentials() { 82 super.eraseCredentials(); 83 if (this.userAuthentication != null && CredentialsContainer.class.isAssignableFrom(this.userAuthentication.getClass())) { 84 CredentialsContainer.class.cast(this.userAuthentication).eraseCredentials(); 85 } 86 } 87 88 @Override 89 public boolean equals(Object o) { 90 if (this == o) { 91 return true; 92 } 93 if (!(o instanceof CustomOAuth2Authentication)) { 94 return false; 95 } 96 if (!super.equals(o)) { 97 return false; 98 } 99 100 CustomOAuth2Authentication that = (CustomOAuth2Authentication) o; 101 102 if (!storedRequest.equals(that.storedRequest)) { 103 return false; 104 } 105 if (userAuthentication != null ? !userAuthentication.equals(that.userAuthentication) 106 : that.userAuthentication != null) { 107 return false; 108 } 109 110 if (getDetails() != null ? !getDetails().equals(that.getDetails()) : that.getDetails() != null) { 111 // return false; 112 } 113 114 return true; 115 } 116 117 @Override 118 public int hashCode() { 119 int result = super.hashCode(); 120 result = 31 * result + storedRequest.hashCode(); 121 result = 31 * result + (userAuthentication != null ? userAuthentication.hashCode() : 0); 122 return result; 123 } 124 125 }
主要在OAuth2Authentication基礎上修改了30-35行代碼spa