2016-07-29 58 views
2

通过实施TokenEnhancer,我成功添加了user_id关于授权服务器端上生成的令牌的附加信息。这里生成的令牌:现在如何访问令牌additionalInformation以验证基于表达式的访问控制

{"access_token":"ccae1713-00d4-49c2-adbf-e699c525d53e","token_type":"bearer","expires_in":31512,"scope":"end-user","user_id":2}

,在资源服务器侧,这是一个完全独立的弹簧项目通过RemoteTokenServices连通,我想用论文信息与方法expression-based access control。比如我想使用添加的user_id数据(它是春天JPA的数据仓库中使用Spring数据休息使用):

@PreAuthorize("#oauth2.hasScope('admin') or #id == authentication.principal.user_id") @Override UserAccount findOne (@P("id") Integer id);

#oauth2.hasScope('admin')按预期工作,但#id == authentication.principal.user_id"部分显然不是。

如何访问添加到令牌上的基于表达式的访问控制的附加数据?

回答

5

所以我找到了自己。关键接口是UserAuthenticationConverter

使用默认提供的DefaultUserAuthenticationConverter类,我们可以设置一个UserDetailsService,它用于设置authentication.principal与UserDetailsS​​ervice返回的UserDetail对象。没有这一点,authentication.principal只设置令牌用户名作为字符串。

这里是我的ResourceServerConfigAdapter的摘录:

@Configuration 
@EnableResourceServer 
protected static class ResourceServerConfiguration 
     extends ResourceServerConfigurerAdapter { 

    @Bean 
    UserDetailsService userDetailsService() { 
     return new UserDetailsServiceImpl(); 
    } 

    @Bean 
    public UserAuthenticationConverter userAuthenticationConverter() { 
     DefaultUserAuthenticationConverter duac 
      = new DefaultUserAuthenticationConverter(); 
     duac.setUserDetailsService(userDetailsService()); 
     return duac; 
    } 

    @Bean 
    public AccessTokenConverter accessTokenConverter() { 
     DefaultAccessTokenConverter datc 
      = new DefaultAccessTokenConverter(); 
     datc.setUserTokenConverter(userAuthenticationConverter()); 
     return datc; 
    } 

    @Bean 
    RemoteTokenServices getRemoteTokenServices() { 
     RemoteTokenServices rts = new RemoteTokenServices(); 
     rts.setCheckTokenEndpointUrl(
      "http://localhost:15574/oauth/check_token"); 
     rts.setAccessTokenConverter(accessTokenConverter()); 
     rts.setClientId("client"); 
     rts.setClientSecret("pass"); 
     return rts; 
    } 

    ... 

} 

另一种方法是重写DefaultUserAuthenticationManager并提供自定义public Authentication extractAuthentication(Map<String, ?> map)

一旦做到这一点,我们可以使用expression-based access control这样的用户数据:

@PreAuthorize("#oauth2.hasScope('admin') or #id == authentication.principal.userAccount.id") 
@Override 
UserAccount findOne (@P("id") Integer id); 

注意userAccount是我原来的域用户对象。它可能是UserDetailsS​​ervice返回的所有内容。

编辑:这里 要回答瓦伦丁Despa,是我的UserDetailsS​​ervice实现:

@Component 
public class UserDetailsServiceImpl implements UserDetailsService { 

    @Autowired 
    UserAccountRepository userAccountRepository; 

    public UserDetails loadUserByUsername (String username) 
      throws UsernameNotFoundException { 

     // Fetch user from repository 
     UserAccount ua = this.userAccountRepository 
      .findByEmail(username); 

     // If nothing throws Exception 
     if (ua == null) { 
      throw new UsernameNotFoundException(
       "No user found having this username"); 
     } 

     // Convert it to a UserDetails object 
     return new UserDetailsImpl(ua); 

    } 

} 
+0

感谢分享。你的UserDetailsS​​erviceImpl是怎么样的? –

+1

我将UserDetailsS​​erviceImpl添加到了答案中。 –

+0

感谢您的快速回复。 –