- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
简介:
我刚开始使用 Spring Boot 。为了理解它是如何工作的,我尝试将我现有的项目(前端的 spring MVC、JSP)转换为在前端使用 REST Controller 和 AngularJS 的 spring boot 方法。
面临的问题:
在迁移过程中,我遇到了安全方面的大问题。据我了解,现在拥有良好安全层的最佳方法是使用 JWT token 并支持 oauth2,其中有很多帖子/教程提供了不同的信息,甚至是关于安全层架构的基础知识。
那么问题是:
有人可以指出安全层部件/类的完整列表,这些是为带有 REST Controller 的 spring boot 应用程序提供基本(但不是 hello world)安全功能所必需的。请不要建议使用stormpath : 我想自己实现它以获得更好的理解。
在这里问这个大问题的原因:
我已经对此主题进行了自己的调查,但我认为我检查过的大多数链接都包含很多不良做法,因此安全层的架构可能不正确。所以我真的很想知道一些设计安全层架构的良好实践。
所需功能的详细信息:
我有我想要支持的标准功能列表。
项目的当前层:
以下是有关我当前项目结构的一些附加信息:目前我已经实现了以下模块:
如果我理解正确,我需要在这里添加两个附加层:
最佳答案
您可以从创建 3 个项目开始。
阅读有关 OAuth2 授权类型的信息。
我们使用 password授权服务器和客户端由同一组织开发时,或者资源所有者与客户端之间存在高度信任时的授权授予类型。
以下是 OAuth2 实现所需的基本类:
扩展 AuthorizationServerConfigurerAdapter
以配置授权服务器的类。在这里您可以配置端点,例如 userDetailsService(自定义类以通过用户名从数据库加载用户数据)、tokenStore(将 token 存储在数据库中并对其执行操作)、clientDetailsService(从数据库加载客户端详细信息;您的 Rest API 项目可以是客户端) .
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
endpoints.userDetailsService(userDetailsService);
endpoints.tokenStore(tokenStore);
endpoints.setClientDetailsService(clientDetailsService);
endpoints.accessTokenConverter(accessTokenConverter);
}
@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
//The expression below easies access to /oauth/check_token endpoint from the default denyAll to isAuthenticated.
oauthServer.checkTokenAccess("isAuthenticated()");
oauthServer.allowFormAuthenticationForClients();
oauthServer.passwordEncoder(passwordEncoder);
}
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
一个扩展 ResourceServerConfigurerAdapter
的类。在这里您可以为资源服务器配置安全配置。资源将是 Auth 服务器中定义的 Rest Controller (例如用于对用户对象执行 CRUD 操作的 Controller 、撤销 token 的端点;需要在 Auth 服务器中的 Controller )。
@Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().fullyAuthenticated(); //To restrict all http requests.
/*http.authorizeRequests().antMatchers("/users/**").permitAll(); //Notice ant matcher here, this tells endpoints which do not require authentication. Lots of http configuration options (like applying filters, cors, csrf etc.) are available here. Please explore*/
}
查看 TokenStore默认实现类(如 JdbcTokenStore
、JwtTokenStore
)。如果您想像 Cassandra 一样使用 NoSQL 数据库,请提供自定义 TokenStore
实现。
以下是用于 Cassandra 的自定义 token 存储的示例代码片段:
@Override
public void storeAccessToken(final OAuth2AccessToken token, final OAuth2Authentication authentication) {
String refreshToken = null;
if (token.getRefreshToken() != null) {
refreshToken = token.getRefreshToken().getValue();
}
if (readAccessToken(token.getValue()) != null) {
removeAccessToken(token.getValue());
}
final AccessTokenBuilder accessTokenBuilder = new AccessTokenBuilder();
accessTokenRepository.save(accessTokenBuilder
.withAuthenticationId(authenticationKeyGenerator.extractKey(authentication))
.withTokenId(extractTokenKey(token.getValue()))
.withTokenBody(ByteBuffer.wrap(serializeAccessToken(token)))
.withUsername(authentication.getName())
.withClientId(authentication.getOAuth2Request().getClientId())
.withAuthentication(ByteBuffer.wrap(serializeAuthentication(authentication)))
.withRefreshTokenId(extractTokenKey(refreshToken))
.build());
}
@Override
public void storeRefreshToken(final OAuth2RefreshToken refreshToken, final OAuth2Authentication authentication) {
final RefreshTokenBuilder refreshTokenBuilder = new RefreshTokenBuilder();
refreshTokenRepository.save(refreshTokenBuilder
.withTokenId(extractTokenKey(refreshToken.getValue()))
.withTokenBody(ByteBuffer.wrap(serializeRefreshToken(refreshToken)))
.withAuthentication(ByteBuffer.wrap(serializeAuthentication(authentication)))
.build());
}
@Override
public OAuth2Authentication readAuthentication(final OAuth2AccessToken token) {
return readAuthentication(token.getValue());
}
@Override
public OAuth2Authentication readAuthentication(final String token) {
OAuth2Authentication authentication = null;
try {
final AccessToken authAccessToken = accessTokenRepository.findByTokenId(extractTokenKey(token));
authentication = deserializeAuthentication(authAccessToken.getAuthentication().array());
} catch (final IllegalArgumentException e) {
removeAccessToken(token);
}
return authentication;
}
@Override
public OAuth2AccessToken readAccessToken(final String tokenValue) {
final AccessToken accessToken = accessTokenRepository.findByTokenId(extractTokenKey(tokenValue));
return accessToken != null ? deserializeAccessToken(accessToken.getTokenBody().array()) : null;
}
@Override
public OAuth2RefreshToken readRefreshToken(final String tokenValue) {
final RefreshToken refreshToken = refreshTokenRepository.findOne(extractTokenKey(tokenValue));
return refreshToken != null ? deserializeRefreshToken(refreshToken.getTokenBody().array()) : null;
}
@Override
public OAuth2Authentication readAuthenticationForRefreshToken(final OAuth2RefreshToken token) {
return readAuthenticationForRefreshToken(token.getValue());
}
OAuth2Authentication readAuthenticationForRefreshToken(final String tokenValue) {
final RefreshToken refreshToken = refreshTokenRepository.findOne(extractTokenKey(tokenValue));
return refreshToken != null ? deserializeAuthentication(refreshToken.getAuthentication().array()) : null;
}
@Override
public OAuth2AccessToken getAccessToken(final OAuth2Authentication authentication) {
OAuth2AccessToken oAuth2AccessToken = null;
final String key = authenticationKeyGenerator.extractKey(authentication);
final AccessToken accessToken = accessTokenRepository.findOne(key);
if (accessToken != null) {
oAuth2AccessToken = deserializeAccessToken(accessToken.getTokenBody().array());
if (oAuth2AccessToken != null && !key.equals(authenticationKeyGenerator.extractKey(readAuthentication(oAuth2AccessToken.getValue())))) {
removeAccessToken(oAuth2AccessToken.getValue());
storeAccessToken(oAuth2AccessToken, authentication);
}
}
return oAuth2AccessToken;
}
您需要为数据库操作声明存储库接口(interface)。扩展 CrudRepository
的接口(interface)。对于大部分的DB操作我们不需要提供实现,由Spring来处理。 Cassandra 的实现在 SimpleCassandraRepository
类中。访问 token 的示例代码:
public interface AccessTokenRepository extends CrudRepository<AccessToken, String> {
@Query("SELECT * FROM auth_service.oauth_access_token WHERE token_id = :tokenId ALLOW FILTERING")
AccessToken findByTokenId(@Param("tokenId") String tokenId);
}
ClientDetails
的示例代码
public interface ClientDetailsRepository extends CrudRepository<ClientDetails, String> {
}
请注意,我们不需要为这些接口(interface)提供实现。常规的 CRUD 查询已经由 Spring 实现和处理。
public interface RefreshTokenRepository extends CrudRepository<RefreshToken, String> {
}
Rest API 项目
当从前端收到请求(来自 javascript 的 AJAX 请求)时,将调用此处声明的 Controller 。所有业务逻辑和持久层都将放在此处。
在这里你可以考虑创建一个模块,一个网关,它与 Auth Server 对话。此网关将位于您的 Rest API 和 Auth Server 之间。您可以使用 RestTemplate调用远程 Rest 服务。
如果您需要任何 Rest API 项目都不能远程调用 Auth Server,那么用户 client_credentials以及 password
授权类型。并且,使用 OAuth2RestTemplate而不是 RestTemplate
。示例代码:
<bean id="oAuth2RestTemplate" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<constructor-arg ref="clientCredentialsResourceDetails"/>
<constructor-arg ref="defaultOAuth2ClientContext"/>
<property name="requestFactory" ref="httpComponentsClientHttpRequestFactory"/>
</bean>
<bean id="httpComponentsClientHttpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg ref="selfSignedHttpsClientFactory"/>
</bean>
<bean id="clientCredentialsResourceDetails" class="org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails">
<property name="accessTokenUri" value="${authentication.service.client.token.url:https://localhost:8443/oauth/token}"/>
<property name="clientId" value="${authentication.service.client.id:testClient}"/>
<property name="clientSecret" value="${authentication.service.client.secret:password}"/>
</bean>
<bean id="defaultOAuth2ClientContext" class="org.springframework.security.oauth2.client.DefaultOAuth2ClientContext"/>
我希望这对您有所帮助。
关于spring-boot - Spring Security with JWT tokens 的主要概念(Spring boot with REST controllers),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44991536/
1. JWT 简介 JSON Web Token(JWT) 是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。该信息可以被验证和信
关于JWT(json web token)的一些问题: 可以在手机上使用吗? 在我看来,它适用于移动设备,但它是否是一个很好的身份验证解决方案?如果不是,还有哪些其他解决方案可用于移动应用程序和服务器
我无法清楚地掌握 JWT 是如何工作的,尤其是。签名部分。 一旦客户端提交正确的用户名和密码,身份验证服务器就会创建一个 JWT token ,其中包含 header 、有效负载/声明和签名。 问题
我正在通过 jwt.io(在调试器部分)解码 JWT token 以查看标题、有效负载。令人惊讶的是,它还验证了,我可以看到它(jwt.io 调试器)也能够检索公钥。 所以我的问题是:JWT toke
我尝试使用 validate-jwt 策略限制使用 JWT token 对 REST API 的访问。以前从来没有这样做过。 这是我的入站策略(取自简单 token 验证here):
我们有一个微服务架构,使用 JWT 在服务之间进行身份验证。我希望轻松地从 JWT 中获取更多字段。目前实际上只有权限由 Spring Security 直接公开。 我们的边缘服务/API 网关创建以
我正在尝试在 .NET 中生成 JWT token 。起初,我尝试使用“System.IdentityModel.Tokens.Jwt”,但它在 token 验证期间引起了问题,所以我切换到“jose
我已经阅读了很多关于 stackOverflow 和 jwt 文档的问题。据我了解,现在我应该如何计算 token : header = { "alg": "HS256", "typ": "J
我想知道我可以设置的 JWT token 到期的最大值是多少。 谢谢! 最佳答案 没有关于过期时间的规定。它主要取决于使用 token 的上下文。 RFC7519 section 4 : The se
我在子域上托管了单独的身份验证应用程序和多个 spa 应用程序,我想将生成的 JWT token (当用户从身份验证应用程序登录时生成)从身份验证应用程序共享到子域下托管的其他应用程序。我怎样才能
据我所知,验证 JWT 签名是一个直接的过程。但是当我使用一些在线工具为我执行此操作时,它不匹配。如何在不使用 JWT 库的情况下手动验证 JWT 签名?我需要一种快速方法(使用可用的在线工具)来演示
我的 JSON 网络 token (JWT): eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6InU0T2ZORlBId0VCb3NIanRyYXVPYlY4
我是 JWT 的新手。我对 JWT 进行了一些研究,并了解到它的框架是“header.claims.signature”。 考虑一个简单的场景,如下所示: 客户通过身份验证 客户可能具有(一个或多个)
我需要知道的最大长度 JSON Web Token (JWT) 在规范中没有相关信息。难道,长度没有限制? 最佳答案 我也一直在努力寻找这个。 我想说 - 尝试确保它低于 7kb。 虽然 JWT 在规
我看到 JWT token 由 A-Z、a-Z、0-9 和特殊字符 - 和 _ 组成。我想知道 JWT token 中允许的字符列表? 最佳答案 来自JWT introduction :“输出是三个用
我正在使用 Jhipster 创建一个应用程序。为此,我想使用 Keycloak 身份验证服务器。但是,一旦我登录,就会收到以下消息:Statut : Internal Server Error (内
我正在使用 Jhipster 创建一个应用程序。为此,我想使用 Keycloak 身份验证服务器。但是,一旦我登录,就会收到以下消息:Statut : Internal Server Error (内
我在我的网站上使用 MEAN 堆栈,用户可以在其中将带有玩家信息的事件(2-4/事件)添加到购物车。有时他们会购买多个事件。我希望此信息不会受到用户操纵(如果他们使用控制台,则在结帐前更改信息),并且
一个 JSON Web token (JWT) 被分成三个 Base-64 编码的部分,这些部分由句点 (“.”) 连接起来。前两部分对 JSON 对象进行编码,第一部分是详细说明签名和散列算法的 h
我正在使用 django rest 框架 JWT 库 http://getblimp.github.io/django-rest-framework-jwt/ JWT token 过期有两个设置 JW
我是一名优秀的程序员,十分优秀!