我目前正在构建一个单页面AngularJS应用程序,该应用程序通过REST与后端进行通信。结构如下:
一个Spring MVC WebApp项目,其中包含所有AngularJS页面和资源以及所有REST控制器。
一个真正的后端,具有用于后端通信的服务和存储库,如果可以的话,还提供一个API。REST调用将与这些服务通信(第二个项目作为第一个项目的依赖项包含在内)。
我已经考虑了很多,但是似乎找不到任何可以帮助我的东西。基本上,我只需要此应用程序的一些安全性。我想要某种非常简单的会话管理:
这是基本会话管理的一般思想,这是在Spring MVC Web应用程序(没有JSP的,只有角度和REST控制器)中实现这一点的最简单方法。
提前致谢!
其余API有2个选项:有状态或无状态。
第一个选项:HTTP会话身份验证-“经典” Spring
Security身份验证机制。如果计划在多台服务器上扩展应用程序,则需要具有带有粘性会话的负载平衡器,以便每个用户都位于同一台服务器上(或将Spring
Session与Redis一起使用)。
第二个选择:您可以选择OAuth或基于令牌的身份验证。
OAuth2是一种无状态的安全性机制,因此,如果要跨多台机器扩展应用程序,则可能更希望使用它。Spring
Security提供了OAuth2实现。OAuth2的最大问题是需要具有多个数据库表才能存储其安全令牌。
与OAuth2一样,基于令牌的身份验证是一种无状态的安全机制,因此,如果要在多个不同的服务器上进行扩展,它是另一个不错的选择。Spring
Security默认情况下不存在此身份验证机制。与OAuth2相比,它更易于使用和实现,因为它不需要持久性机制,因此它适用于所有SQL和NoSQL选项。此解决方案使用自定义令牌,该令牌是您的用户名,令牌的到期日期,密码和密钥的MD5哈希。这样可以确保如果有人窃取了您的令牌,那么他将无法提取您的用户名和密码。
我建议您研究JHipster。它将使用REST
API(使用Spring
Boot)和前端(使用AngularJS)为您生成一个Web应用程序框架。生成应用程序框架时,它将要求您在我上面描述的3种身份验证机制之间进行选择。您可以重用JHipster在Spring
MVC应用程序中生成的代码。
这是JHipster生成的TokenProvider的示例:
public class TokenProvider {
private final String secretKey;
private final int tokenValidity;
public TokenProvider(String secretKey, int tokenValidity) {
this.secretKey = secretKey;
this.tokenValidity = tokenValidity;
}
public Token createToken(UserDetails userDetails) {
long expires = System.currentTimeMillis() + 1000L * tokenValidity;
String token = userDetails.getUsername() + ":" + expires + ":" + computeSignature(userDetails, expires);
return new Token(token, expires);
}
public String computeSignature(UserDetails userDetails, long expires) {
StringBuilder signatureBuilder = new StringBuilder();
signatureBuilder.append(userDetails.getUsername()).append(":");
signatureBuilder.append(expires).append(":");
signatureBuilder.append(userDetails.getPassword()).append(":");
signatureBuilder.append(secretKey);
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("No MD5 algorithm available!");
}
return new String(Hex.encode(digest.digest(signatureBuilder.toString().getBytes())));
}
public String getUserNameFromToken(String authToken) {
if (null == authToken) {
return null;
}
String[] parts = authToken.split(":");
return parts[0];
}
public boolean validateToken(String authToken, UserDetails userDetails) {
String[] parts = authToken.split(":");
long expires = Long.parseLong(parts[1]);
String signature = parts[2];
String signatureToMatch = computeSignature(userDetails, expires);
return expires >= System.currentTimeMillis() && signature.equals(signatureToMatch);
}
}
安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Inject
private Http401UnauthorizedEntryPoint authenticationEntryPoint;
@Inject
private UserDetailsService userDetailsService;
@Inject
private TokenProvider tokenProvider;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/scripts/**/*.{js,html}");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/protected/**").authenticated()
.and()
.apply(securityConfigurerAdapter());
}
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
private static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
}
private XAuthTokenConfigurer securityConfigurerAdapter() {
return new XAuthTokenConfigurer(userDetailsService, tokenProvider);
}
/**
* This allows SpEL support in Spring Data JPA @Query definitions.
*
* See https://spring.io/blog/2014/07/15/spel-support-in-spring-data-jpa-query-definitions
*/
@Bean
EvaluationContextExtension securityExtension() {
return new EvaluationContextExtensionSupport() {
@Override
public String getExtensionId() {
return "security";
}
@Override
public SecurityExpressionRoot getRootObject() {
return new SecurityExpressionRoot(SecurityContextHolder.getContext().getAuthentication()) {};
}
};
}
}
以及相应的AngularJS配置:
'use strict';
angular.module('jhipsterApp')
.factory('AuthServerProvider', function loginService($http, localStorageService, Base64) {
return {
login: function(credentials) {
var data = "username=" + credentials.username + "&password="
+ credentials.password;
return $http.post('api/authenticate', data, {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json"
}
}).success(function (response) {
localStorageService.set('token', response);
return response;
});
},
logout: function() {
//Stateless API : No server logout
localStorageService.clearAll();
},
getToken: function () {
return localStorageService.get('token');
},
hasValidToken: function () {
var token = this.getToken();
return token && token.expires && token.expires > new Date().getTime();
}
};
});
authInterceptor:
.factory('authInterceptor', function ($rootScope, $q, $location, localStorageService) {
return {
// Add authorization token to headers
request: function (config) {
config.headers = config.headers || {};
var token = localStorageService.get('token');
if (token && token.expires && token.expires > new Date().getTime()) {
config.headers['x-auth-token'] = token.token;
}
return config;
}
};
})
将authInterceptor添加到$ httpProvider中:
.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
})
希望这会有所帮助!
本文向大家介绍如何实现 Spring Boot 应用程序的安全性?相关面试题,主要包含被问及如何实现 Spring Boot 应用程序的安全性?时的应答技巧和注意事项,需要的朋友参考一下 为了实现 Spring Boot 的安全性,我们使用 spring-boot-starter-security 依赖项,并且必须添加安全配置。它只需要很少的代码。配置类将必须扩展 WebSecurityConfi
本文向大家介绍如何在Spring Boot应用程序中实现Spring安全性?相关面试题,主要包含被问及如何在Spring Boot应用程序中实现Spring安全性?时的应答技巧和注意事项,需要的朋友参考一下 实施需要最少的配置。您需要做的就是spring-boot-starter-security在pom.xml文件中添加starter。您还需要创建一个Spring配置类,它将覆盖所需的方法,同时
我想在前端构建一个干净的Spring Boot应用程序。我的要求是: 应用程序基于浏览器 这些都是非常基本的要求,但我对保护web应用程序的可能性一无所知。有没有标准的推荐方法?我真的试着从一开始就学习教程https://spring.io/guides/tutorials/spring-security-and-angular-js/但由于混合了几个可能的解决方案,而不是描述一个,所以它非常令人
我有一个Android应用程序,我可以在其中向一个servlet发送多部分post。但我要把电话限制在每5分钟一次。有了web表单,我就可以使用cookie了。对于android应用程序,它不是这样工作的。我怎么才能让它工作呢?
问题内容: 有没有办法在Jersey中以编程方式获得会话管理或安全性,例如Web应用程序会话管理?还是事务,会话和安全性都由部署Jersey应用程序的容器处理? 问题答案: 会话管理是部署Jersey的容器的权限。在大多数生产情况下,它将部署在执行会话管理的容器中。 下面的代码是jersey资源的简单示例,该资源获取会话对象并在会话中存储值,并在后续调用中检索它们。
如何从注释中提取操作和对象参数? 如何解析对象定义中的SpEL表达式并将对象作为'act'参数传递?