Spring security 如何使用Spring云安全定制Principle对象?
我终于让我的oauth2服务器运行起来了 从命令行,如果我运行Spring security 如何使用Spring云安全定制Principle对象?,spring-security,spring-security-oauth2,spring-cloud,Spring Security,Spring Security Oauth2,Spring Cloud,我终于让我的oauth2服务器运行起来了 从命令行,如果我运行 curl -s -u acme:acmesecret -d grant_type=password -d username=myusername -d password=mypassword -H Accept:application/json http://localhost:9999/oauth/token 我得到了下面的结果 { "access_token":"eyJhbGciOiJSUzI1NiJ9.eyJleH
curl -s -u acme:acmesecret -d grant_type=password -d username=myusername -d password=mypassword -H Accept:application/json http://localhost:9999/oauth/token
我得到了下面的结果
{
"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Mzk1NDU3ODAsInVzZXJfbmFtZSI6IisxIDQwODUxODIxMTUiLCJhdXRob3JpdGllcyI6WyJVU0VSIiwiQURNSU4iXSwianRpIjoiYmFkMDgyMjctNDExNC00OTZkLWE1NDMtYzBhMjc3YTBhZDkzIiwiY2xpZW50X2lkIjoiYWNtZSIsInNjb3BlIjpbIndlYnNob3AiXX0.CM_0gBHVyecOMmpc2cnKTus48PNv8gfHDyzVOVa5TBDxv4QlnDO93otmUs86IQqPaqaI133tT1NPU0pt2dbV5lrY3FOlPFXB0zZw5ptIXCtpaQLgl3e9hkB1aSfv3YxbHiOV8n3FcvNdz9Ihi9XEQdzqT8YfK7mCeMOjdb1i6Ve9axwjJI9ZHxXzDMcJsnYBcQCKG52G3-rWzgzlaQkPZY6mO7q0eO0jgVWthLfSBumHlDt9QXaBkETH3CRHxSuJqlo4J3TZxP4-1vPLkgh8Ku2rY5A9rT-xOKG8_5s2CJduCZt0qQrXZhz7sk0m2IdxDDwXumPv6zyHyD2J3sjHUA",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX25hbWUiOiIrMSA0MDg1MTgyMTE1Iiwic2NvcGUiOlsid2Vic2hvcCJdLCJhdGkiOiJiYWQwODIyNy00MTE0LTQ5NmQtYTU0My1jMGEyNzdhMGFkOTMiLCJleHAiOjE0NDIwOTQ1ODAsImF1dGhvcml0aWVzIjpbIlVTRVIiLCJBRE1JTiJdLCJqdGkiOiJjYWNkOWEzOC1mOWE5LTQ4NjAtOWZmMi05NWMzMzU4MmY0NDAiLCJjbGllbnRfaWQiOiJhY21lIn0.DhaqIEdYWR2VPkgh72bQ17ZLqcVVfdYtT8DdKibjIcZUTNNjN_atdyKYKNEtdSyEES-ArHL0jCVXUg3EKiut_qtvn8oaLYEAxCNfztHyo_b-RZIxOgr71m82n66vSwRzxQnoKcGltxpZs-PK5p-gmbaEWK4EO63AkJpgN_IrIGV4eVQmidanz53rvq-CBiq-1FFb64OilesUxkSPOVkbb-q-mUmd8EG4khdbf44LD9VhyZwt8lOOi8NnksnnGhogiynU9p7tirAv6w_g8IO7uy06fWaLyn6rAgPga3CYgo9ggFIICWKn-QFipkHgiehq6y_1-xTGlgHnRKXcnPIZcg",
"expires_in": 34996,
"scope": "webshop",
"jti": "bad08227-4114-496d-a543-c0a277a0ad93"
}
返回令牌后,我可以使用curl命令获取用户信息。您可以在响应中查看大量用户信息
curl http://localhost:9999/user -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Mzk1NDU3ODAsInVzZXJfbmFtZSI6IisxIDQwODUxODIxMTUiLCJhdXRob3JpdGllcyI6WyJVU0VSIiwiQURNSU4iXSwianRpIjoiYmFkMDgyMjctNDExNC00OTZkLWE1NDMtYzBhMjc3YTBhZDkzIiwiY2xpZW50X2lkIjoiYWNtZSIsInNjb3BlIjpbIndlYnNob3AiXX0.CM_0gBHVyecOMmpc2cnKTus48PNv8gfHDyzVOVa5TBDxv4QlnDO93otmUs86IQqPaqaI133tT1NPU0pt2dbV5lrY3FOlPFXB0zZw5ptIXCtpaQLgl3e9hkB1aSfv3YxbHiOV8n3FcvNdz9Ihi9XEQdzqT8YfK7mCeMOjdb1i6Ve9axwjJI9ZHxXzDMcJsnYBcQCKG52G3-rWzgzlaQkPZY6mO7q0eO0jgVWthLfSBumHlDt9QXaBkETH3CRHxSuJqlo4J3TZxP4-1vPLkgh8Ku2rY5A9rT-xOKG8_5s2CJduCZt0qQrXZhz7sk0m2IdxDDwXumPv6zyHyD2J3sjHUA"
{
"details": {
"remoteAddress": "127.0.0.1",
"sessionId": null,
"tokenValue": "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Mzk1NDU3ODAsInVzZXJfbmFtZSI6IisxIDQwODUxODIxMTUiLCJhdXRob3JpdGllcyI6WyJVU0VSIiwiQURNSU4iXSwianRpIjoiYmFkMDgyMjctNDExNC00OTZkLWE1NDMtYzBhMjc3YTBhZDkzIiwiY2xpZW50X2lkIjoiYWNtZSIsInNjb3BlIjpbIndlYnNob3AiXX0.CM_0gBHVyecOMmpc2cnKTus48PNv8gfHDyzVOVa5TBDxv4QlnDO93otmUs86IQqPaqaI133tT1NPU0pt2dbV5lrY3FOlPFXB0zZw5ptIXCtpaQLgl3e9hkB1aSfv3YxbHiOV8n3FcvNdz9Ihi9XEQdzqT8YfK7mCeMOjdb1i6Ve9axwjJI9ZHxXzDMcJsnYBcQCKG52G3-rWzgzlaQkPZY6mO7q0eO0jgVWthLfSBumHlDt9QXaBkETH3CRHxSuJqlo4J3TZxP4-1vPLkgh8Ku2rY5A9rT-xOKG8_5s2CJduCZt0qQrXZhz7sk0m2IdxDDwXumPv6zyHyD2J3sjHUA",
"tokenType": "Bearer",
"decodedDetails": null
},
"authorities": [
{
"authority": "USER"
},
{
"authority": "ADMIN"
}
],
"authenticated": true,
"userAuthentication": {
"details": {
"grant_type": "password",
"username": "myusername"
},
"authorities": [
{
"authority": "USER"
},
{
"authority": "ADMIN"
}
],
"authenticated": true,
"principal": {
"id": "usr000d11b4c86-13ba-11e5-b905-56847afe9799",
"json": null,
"version": 0,
"created": 1434412879774,
"updated": 1438877901186,
"info": {
"nickName": "Kevin",
"country": "China",
"zipcode": null,
"state": null,
"city": "",
"occupation": "",
"gender": null,
"imgPath": "https://ddbs0erhouflt.cloudfront.net/mcf000ecd36bcb-f33e-4d50-9102-7a8706b45eb8",
"about": "",
"dueDate": 1447312895201,
"birthday": 0
},
"privateInfo": {
"email": "zyj@yahoo.com",
"phone": "myusername",
"password": "f45206ce4247b5d9af350d4600adc85c",
"tempPassword": null,
"tokens": null
},
"settings": null,
"type": "Super",
"status": "Active",
"enabled": true,
"username": "myusername",
"password": "f45206ce4247b5d9af350d4600adc85c",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"authorities": [
{
"authority": "USER"
},
{
"authority": "ADMIN"
}
]
},
"credentials": null,
"name": "myusername"
},
"credentials": "",
"oauth2Request": {
"clientId": "acme",
"scope": [
"webshop"
],
"requestParameters": {
"grant_type": "password",
"username": "myusername"
},
"resourceIds": [],
"authorities": [],
"approved": true,
"refresh": false,
"redirectUri": null,
"responseTypes": [],
"extensions": {},
"grantType": "password",
"refreshTokenRequest": null
},
"principal": {
"id": "usr000d11b4c86-13ba-11e5-b905-56847afe9799",
"json": null,
"version": 0,
"created": 1434412879774,
"updated": 1438877901186,
"info": {
"nickName": "Kevin",
"country": "China",
"zipcode": null,
"state": null,
"city": "",
"occupation": "",
"gender": null,
"imgPath": "https://ddbs0erhouflt.cloudfront.net/mcf000ecd36bcb-f33e-4d50-9102-7a8706b45eb8",
"about": "",
"dueDate": 1447312895201,
"birthday": 0
},
"privateInfo": {
"email": "zyj@yahoo.com",
"phone": "myusername",
"password": "f45206ce4247b5d9af350d4600adc85c",
"tempPassword": null,
"tokens": null
},
"settings": null,
"type": "Super",
"status": "Active",
"enabled": true,
"username": "myusername",
"password": "f45206ce4247b5d9af350d4600adc85c",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"authorities": [
{
"authority": "USER"
},
{
"authority": "ADMIN"
}
]
},
"clientOnly": false,
"name": "myusername"
}
我有一个Spring boot微服务客户端。它使用spring云安全。下面是一个web服务
@RequestMapping(value="getsth", method=RequestMethod.GET)
public SomeObject getsth(Principal principal) {
....
}
调用getsth方法时,我可以看到传入了OAuth2Authentication的对象。但是,缺少用户id、用户电话号码等用户信息
我的问题:如何获取所有用户信息?有没有办法自定义主对象
谢谢,要定制它,您必须提供自己的UserDetails服务类:
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username);
}
}
其中,User
是您的实体,包含您需要的所有字段:
public class User implements Serializable, UserDetails {...
然后,您必须配置SpringSecurity以实际使用自定义用户详细信息服务。类似于:
@Configuration
@EnableWebMvcSecurity
@EnableGlobalAuthentication
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.parentAuthenticationManager(authenticationManager)
.userDetailsService(myUserDetailsService);
}
我也在为同样的问题挣扎。不过我还是让它工作了 我使用的是JWT,所以可能与您所做的略有不同,但概念是相同的 首先,我创建了一个自定义TokenServices来获取用户的额外信息,并将其添加到身份验证对象中:
public class TafTokenServices extends DefaultTokenServices {
@Override
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
final TafUserDetails tafUserDetails = (TafUserDetails)authentication.getPrincipal();
final Map<String, Object> tafInfo = new HashMap<>();
tafInfo.put("EMAIL", tafUserDetails.getEmailAddress());
authentication.setDetails(tafInfo);
return super.createAccessToken(authentication);
}
此外,在身份验证服务器中,您还需要使用自己的AccessTokenCoverter对象将数据从身份验证对象传输到令牌:
public class TafJwtAccessTokenConverter extends JwtAccessTokenConverter {
private static final String EMAIL_KEY = "EMAIL";
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
final Map<String, Object> authDetails = (Map<String, Object>)authentication.getDetails();
((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(authDetails);
return super.enhance(accessToken, authentication);
}
@Override
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
final OAuth2Authentication authentication = super.extractAuthentication(map);
final Map<String, String> details = new HashMap<>();
details.put(EMAIL_KEY, (String)map.get(EMAIL_KEY));
authentication.setDetails(details);
return authentication;
}
}
公共类TafJwtAccessTokenConverter扩展了JwtAccessTokenConverter{
私有静态最终字符串EMAIL\u KEY=“EMAIL”;
@凌驾
公共OAuth2AccessToken增强(OAuth2AccessToken accessToken,OAuth2Authentication身份验证){
final Map authDetails=(Map)authentication.getDetails();
((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(authDetails);
返回super.enhance(accessToken、身份验证);
}
@凌驾
公共OAuth2Authentication extractAuthentication(映射){
最终OAuth2AuthenticationAuthentication=super.extractAuthentication(map);
final Map details=new HashMap();
details.put(EMAIL_KEY,(String)map.get(EMAIL_KEY));
验证。设置详细信息(详细信息);
返回认证;
}
}
注意:Enhanced()方法是在创建令牌期间调用的,因此您需要在auth服务器中使用它
注意:extractAuthentication()是在身份验证期间在下游服务中调用的,因此该实现也需要存在于下游服务中。您需要配置资源服务器以使用此AccessTokenConverter
这将使信息进入令牌以向下游传递。注意,我不想将数据保留在自定义用户对象中,因为我不想让我的其他服务依赖于该对象
下一步是从令牌中取出内容,并在资源服务器中使用它。您可以通过重写extractAuthentication()从映射中获取详细信息,并将其放入身份验证对象中来实现这一点。通过执行以下操作,您的应用程序中现在可以使用它们:
private String getEmail() {
final OAuth2Authentication auth = this.getAuthentication();
final OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)auth.getDetails();
final Map<String, Object> map = (Map)details.getDecodedDetails();
return "Your email address is " + map.get("EMAIL");
}
private OAuth2Authentication getAuthentication() {
return (OAuth2Authentication)SecurityContextHolder.getContext().getAuthentication();
}
private String getEmail(){
最终OAuth2Authentication auth=this.getAuthentication();
最终OAuth2AuthenticationDetails=(OAuth2AuthenticationDetails)auth.getDetails();
最终映射=(映射)详细信息。getDecodedDetails();
返回“您的电子邮件地址为”+map.get(“电子邮件”);
}
私有OAuth2Authentication getAuthentication(){
返回(OAuth2Authentication)SecurityContextHolder.getContext().getAuthentication();
}
我不确定这是不是正确的方式,这有点烦躁。我有一个问题需要讨论:
这不是我想要的。谢谢freakman回答我的问题。但答案不是我想要的。实际上,我已经在oauth服务器A端实现了定制的UserDetails。这类似于“公共类用户扩展实现UserDetails”。一切正常。我的问题是我有另一个受oauth保护的应用程序B。它是一个独立的spring boot应用程序,用@EnableOAuth2Resource注释。我上面提到的代码段“publicsomeobjectgetsth(Principal)”位于服务器B端。我的问题是如何在应用程序B上获取用户对象而不是主体。我也有同样的情况。主体仅包含经过身份验证的用户的名称。我想获得用户id/uuid/电子邮件,这也是我自己的UserDetails服务的一部分@张永江,你是不是按你的意思来做的?我的情况也和你一样菲利普,你有没有找到任何方法来获取用户id?这很奇怪,默认情况下不支持它,因为通常使用userId
private String getEmail() {
final OAuth2Authentication auth = this.getAuthentication();
final OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)auth.getDetails();
final Map<String, Object> map = (Map)details.getDecodedDetails();
return "Your email address is " + map.get("EMAIL");
}
private OAuth2Authentication getAuthentication() {
return (OAuth2Authentication)SecurityContextHolder.getContext().getAuthentication();
}