网站后台培训方案,上海市建设工程交易平台,优质校建设网站,网站开发分为前端和后台1.概述 本文重点介绍如何针对提供安全服务的安全REST API进行身份验证 -主要是RESTful用户帐户和身份验证服务。 2.目标 首先#xff0c;让我们看一下参与者-典型的启用了Spring Security的应用程序需要针对某些事物进行身份验证-该事物可以是数据库#xff0c;LDAP或可以是… 1.概述 本文重点介绍如何针对提供安全服务的安全REST API进行身份验证 -主要是RESTful用户帐户和身份验证服务。 2.目标 首先让我们看一下参与者-典型的启用了Spring Security的应用程序需要针对某些事物进行身份验证-该事物可以是数据库LDAP或可以是REST服务。 数据库是最常见的情况。 但是RESTful UAA用户帐户和身份验证服务也可以正常工作。 就本文而言REST UAA服务将在/ authentication上公开一个GET操作该操作将返回 Spring Security执行完整身份验证过程所需的Principal信息 。 3.客户 通常启用了Spring Security的简单应用程序将使用简单的用户服务作为身份验证源 authentication-manager aliasauthenticationManagerauthentication-provider user-service-refcustomUserDetailsService /
/authentication-manager 这将实现org.springframework.security.core.userdetails.UserDetailsService并将基于提供的用户名 返回Principal Component
public class CustomUserDetailsService implements UserDetailsService {Overridepublic UserDetails loadUserByUsername(String username) { ...}
} 当客户端通过RESTful UAA服务进行身份验证时仅使用用户名 已不再足够 -客户端现在将身份验证请求发送到服务时需要完整的凭据包括用户名和密码 。 由于服务本身是安全的因此这很有意义因此请求本身必须包含身份验证凭据才能正确处理。 从Spring Security的角度来看不能在loadUserByUsername内完成此操作因为此时密码不再可用-我们需要尽快控制身份验证过程。 我们可以通过向Spring Security提供完整的身份验证提供程序来做到这一点 authentication-manager aliasauthenticationManagerauthentication-provider refrestAuthenticationProvider /
/authentication-manager 覆盖整个身份验证提供程序使我们有更多的自由来执行从服务中自定义的委托人检索但是确实带来了相当大的复杂性。 标准身份验证提供程序– DaoAuthenticationProvider –满足了我们的大部分需求因此一种好的方法是简单地扩展它并仅修改必要的内容。 不幸的是这是不可能的因为retrieveUser 我们希望扩展的方法是final 。 这有点不直观有一个JIRA讨论了这个问题 –看起来这里的设计意图仅仅是提供一个不理想的替代实现但也不是主要问题–我们的RestAuthenticationProvider复制并粘贴了大多数实现DaoAuthenticationProvider并重写所需的内容–从服务中检索主体 Override
protected UserDetails retrieveUser(String name, UsernamePasswordAuthenticationToken auth){String password auth.getCredentials().toString();UserDetails loadedUser null;try {ResponseEntityPrincipal authenticationResponse authenticationApi.authenticate(name, password);if (authenticationResponse.getStatusCode().value() 401) {return new User(wrongUsername, wrongPass, Lists.GrantedAuthority newArrayList());}Principal principalFromRest authenticationResponse.getBody();SetString privilegesFromRest Sets.newHashSet(); // fill in the privilegesFromRest from the PrincipalString[] authoritiesAsArray privilegesFromRest.toArray(new String[privilegesFromRest.size()]);ListGrantedAuthority authorities AuthorityUtils.createAuthorityList(authoritiesAsArray);loadedUser new User(name, password, true, authorities);} catch (Exception ex) {throw new AuthenticationServiceException(repositoryProblem.getMessage(), ex);}return loadedUser;
} 让我们从头开始 -与REST服务的HTTP通信-这由authenticationApi处理 authenticationApi是提供实际服务的身份验证操作的简单API。 可以使用任何支持HTTP的库来实现操作本身–在这种情况下实现是使用RestTemplate进行的 public ResponseEntityPrincipal authenticate(String username, String pass) {HttpEntityPrincipal entity new HttpEntityPrincipal(createHeaders(username, pass))return restTemplate.exchange(authenticationUri, HttpMethod.GET, entity, Principal.class);
}HttpHeaders createHeaders(String email, String password) {HttpHeaders acceptHeaders new HttpHeaders() {{set(com.google.common.net.HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString());}};String authorization username : password;String basic new String(Base64.encodeBase64(authorization.getBytes(Charset.forName(US-ASCII))));acceptHeaders.set(Authorization, Basic basic);return acceptHeaders;
} FactoryBean可用于在上下文中设置RestTemplate 。 接下来 如果身份验证请求导致HTTP 401 Unauthorized 很可能是由于来自客户端的不正确凭据则返回具有错误凭据的主体以便Spring Security身份验证过程可以拒绝它们 return new User(wrongUsername, wrongPass, Lists.GrantedAuthority newArrayList()); 最后Spring Security Principal需要一些权限-特定主体在身份验证过程后将拥有并在本地使用的特权。 / authenticate操作已经检索了包括特权的完整主体因此需要按照Spring Security的要求从请求的结果中提取这些特权并将其转换为GrantedAuthority对象。 这些特权的存储方式在这里无关紧要-它们可以存储为简单的String或复杂的Role-Privilege结构-但无论细节如何我们只需要使用它们的名称来构造GrantedAuthoritiy对象。 创建最终的Spring Security主体后将其返回到标准身份验证过程 ListGrantedAuthority authorities AuthorityUtils.createAuthorityList(authoritiesAsArray);
loadedUser new User(name, password, true, authorities);4.测试身份验证服务 编写一个在幸福路径上使用身份验证REST服务的集成测试非常简单 Test
public void whenAuthenticating_then200IsReceived() {// WhenResponseEntityPrincipal response authenticationRestTemplate.authenticate(admin, adminPass);// ThenassertThat(response.getStatusCode().value(), is(200));
} 完成此简单测试之后也可以实施更复杂的集成测试-但这不在本文讨论范围之内。 5.结论 本文介绍了如何针对REST服务进行身份验证而不是针对本地系统如数据库进行身份验证。 有关可以用作身份验证提供程序的安全RESTful服务的完整实现请查看github项目 。 参考来自baeldung博客的JCG合作伙伴 Eugen Paraschiv 通过Spring Security对REST服务进行身份验证 。 翻译自: https://www.javacodegeeks.com/2012/12/authentication-against-a-restful-service-with-spring-security.html