先看源碼是如何處理的:

package org.springframework.boot.autoconfigure.security.oauth2.resource; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.client.OAuth2RestOperations; import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.OAuth2Request; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; import org.springframework.util.Assert; public class UserInfoTokenServices implements ResourceServerTokenServices { protected final Log logger = LogFactory.getLog(this.getClass()); private final String userInfoEndpointUrl; private final String clientId; private OAuth2RestOperations restTemplate; private String tokenType = "Bearer"; private AuthoritiesExtractor authoritiesExtractor = new FixedAuthoritiesExtractor(); private PrincipalExtractor principalExtractor = new FixedPrincipalExtractor(); public UserInfoTokenServices(String userInfoEndpointUrl, String clientId) { this.userInfoEndpointUrl = userInfoEndpointUrl; this.clientId = clientId; } public void setTokenType(String tokenType) { this.tokenType = tokenType; } public void setRestTemplate(OAuth2RestOperations restTemplate) { this.restTemplate = restTemplate; } public void setAuthoritiesExtractor(AuthoritiesExtractor authoritiesExtractor) { Assert.notNull(authoritiesExtractor, "AuthoritiesExtractor must not be null"); this.authoritiesExtractor = authoritiesExtractor; } public void setPrincipalExtractor(PrincipalExtractor principalExtractor) { Assert.notNull(principalExtractor, "PrincipalExtractor must not be null"); this.principalExtractor = principalExtractor; } /** 根據access_token獲取用戶認證信息(根據access_token調用認證服務器) */ public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException { //this.userInfoEndpointUrl application.peoperties中配置的 //獲取用戶信息的URL security.oauth2.resource.userInfoUri //accessToken 回去的access_token //以下為根據access_token和獲取用戶信息的URL(需要則認證服務器寫專門的controller處理)獲取用戶信息 Map<String, Object> map = this.getMap(this.userInfoEndpointUrl, accessToken); if (map.containsKey("error")) { if (this.logger.isDebugEnabled()) { this.logger.debug("userinfo returned error: " + map.get("error")); } throw new InvalidTokenException(accessToken); } else { return this.extractAuthentication(map); } } /** 提取用戶認證信息 */ private OAuth2Authentication extractAuthentication(Map<String, Object> map) { Object principal = this.getPrincipal(map); List<GrantedAuthority> authorities = this.authoritiesExtractor.extractAuthorities(map); OAuth2Request request = new OAuth2Request((Map)null, this.clientId, (Collection)null, true, (Set)null, (Set)null, (String)null, (Set)null, (Map)null); //將提取的值principal作為構造函數參數 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(principal, "N/A", authorities); token.setDetails(map); return new OAuth2Authentication(request, token); } /** 從map中提取最終在UsernamePasswordAuthenticationToken構造函數中封裝的值 */ protected Object getPrincipal(Map<String, Object> map) { Object principal = this.principalExtractor.extractPrincipal(map); return principal == null ? "unknown" : principal; } public OAuth2AccessToken readAccessToken(String accessToken) { throw new UnsupportedOperationException("Not supported: read access token"); } /** 調用認證服務器,獲取用戶信息 */ private Map<String, Object> getMap(String path, String accessToken) { if (this.logger.isDebugEnabled()) { this.logger.debug("Getting user info from: " + path); } try { OAuth2RestOperations restTemplate = this.restTemplate; if (restTemplate == null) { BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails(); resource.setClientId(this.clientId); restTemplate = new OAuth2RestTemplate(resource); } OAuth2AccessToken existingToken = ((OAuth2RestOperations)restTemplate).getOAuth2ClientContext().getAccessToken(); if (existingToken == null || !accessToken.equals(existingToken.getValue())) { DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(accessToken); token.setTokenType(this.tokenType); ((OAuth2RestOperations)restTemplate).getOAuth2ClientContext().setAccessToken(token); } //通過restTemplate返回用戶信息 return (Map)((OAuth2RestOperations)restTemplate).getForEntity(path, Map.class, new Object[0]).getBody(); } catch (Exception var6) { this.logger.warn("Could not fetch user details: " + var6.getClass() + ", " + var6.getMessage()); return Collections.singletonMap("error", "Could not fetch user details"); } } }

/** 最終在map中提取的是什么信息,封裝在principal中 注意:以下只會返回一個合適的值,即使你認證服務返回在多的信息,最終都無法在客戶端顯示 */ public class FixedPrincipalExtractor implements PrincipalExtractor { // private static final String[] PRINCIPAL_KEYS = new String[] { "user", "username", "userid", "user_id", "login", "id", "name" }; @Override public Object extractPrincipal(Map<String, Object> map) { //提取只會返回一個合適的值,最終封裝在principal中 //主要還是看認證服務器返回用戶信息的接口是否返回如上數組定義的字段信息,如果沒有可能會返回null for (String key : PRINCIPAL_KEYS) { if (map.containsKey(key)) { return map.get(key); } } return null; } }

解決方案
只需要將源碼中的以下代碼,替換為自己想要返回的參數
protected Object getPrincipal(Map<String, Object> map) { Object principal = this.principalExtractor.extractPrincipal(map); return principal == null ? "unknown" : principal; }

自己實現的代碼
protected Object getPrincipal(Map<String, Object> map) { CustomPrincipal customPrincipal = new CustomPrincipal(); customPrincipal.setEmail((String) map.get("email")); customPrincipal.setAccount((String) map.get("account")); customPrincipal.setName((String) map.get("name")); customPrincipal.setPhone((String) map.get("phone")); //and so on.. return customPrincipal; /* Object principal = this.principalExtractor.extractPrincipal(map); return (principal == null ? "unknown" : principal); */ }

import com.alibaba.fastjson.JSONObject; /** * @author Created by niugang on 2019/1/18/20:19 */ public class CustomPrincipal { public CustomPrincipal() { } private String email; private String name; private String account; private String phone; //Getters and Setters public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } /** * 因為在principal.getName()返回的參數是字符串類型的,所以為了好處理我們需要用json用格式化一下 * @return String */ @Override public String toString() { JSONObject jsonObject = new JSONObject(); jsonObject.put("email", this.email); jsonObject.put("name", this.name); jsonObject.put("account", this.account); jsonObject.put("phone", this.phone); return jsonObject.toString(); } }

前端獲取用戶新 ,注意這塊中的是freemarker,采坑點好久沒有寫freemarker一直認為springboot默認 freemarker后綴為.html,結果一直不能返回到視圖,最終看了源碼默認后綴為.ftl
- 總結:對於我們平常寫代碼,一丁點小知識點都不能忽略
前后調用接口獲取需要顯示的用戶信息
<script type="text/javascript"> $.get("/getUserInfo", function (data) { if (data) { $("#account").html(data.account); $("#email").html(data.email); $("#name").html(data.name); $("#phone").html(data.phone); } }); </script>

后台返回用戶信息接口
/** * @param principal 存在登錄成功后的信息 * @return Object */ @RequestMapping({"/getUserInfo"}) @ResponseBody public Object user(Principal principal) { if (principal != null) { //重寫之后 principal.getName()存放是 CustomPrincipal toString形式的數據 String jsonObject = principal.getName(); if (jsonObject != null) { CustomPrincipal customPrincipal = JSON.parseObject(jsonObject, CustomPrincipal.class); return customPrincipal; } } return new Object(); }

注意:以上並非全部代碼,只是重點核心代碼,額外的配置參考
以前顯示:
優化后:
https://gitee.com/niugangxy/springcloudAction
微信公眾號

