使用Liferay在REST服务中进行身份验证和授权 [英] Authentication and authorization in REST Services with Liferay
问题描述
我们正在构建一些将通过RESTful API公开的服务.该API的主要客户是使用Angular JS的Liferay Portlet,这意味着可以直接从客户端(Angular)调用我们的服务.
We are building some services that will be exposed through a RESTful API. Primary customers of this API are Liferay portlets using Angular JS, meaning there are direct calls from client-side (Angular) to our services.
到目前为止,我们已经设计了一种身份验证和授权机制,以确保我们可以识别哪个登录用户(Liferay)正在请求我们的API .
So far we have designed an authentication and authorization mechanism to assure that we can identify which logged user (Liferay) is requesting our API.
PS .:请注意,尽管我们使用Liferay,但它可以是任何其他基于Java的应用程序.
我们设计的是:
- 当用户登录我们的门户网站时,Liferay将使用userLogin(或ID)+客户端IP +时间戳创建身份验证令牌.此令牌保存在cookie中;
- 在每个REST调用之前,Angular会读取此cookie并通过HTTP标头发送其内容;
- 我们的服务解密"所发送的cookie内容,并验证时间戳是否有效,IP是否相同以及根据我们的业务规则是否允许用户访问或读取他想要的内容.
该设计现在对我们来说看起来是一致的,并且根据我们选择创建此令牌的算法,我们认为这是一种安全的方法.
This design looks consistent to us right now and, depending on the algorithm we choose to create this token, we believe it is a secure approach.
我们的疑问是:
- 我们是否在某种程度上重新发明了不使用HTTP身份验证和自定义提供程序的轮子?怎么办?
- Spring Security可以帮助我们吗?我们已经阅读了一些有关它的文章,但尚不清楚将其用于非Spring应用程序是否有意义;
- 这种方法是否存在我们未考虑的安全漏洞?
先谢谢您.感谢您的帮助.
Thank you in advance. Any help is appreciated.
Filipe
推荐答案
Spring security解决了问题描述,此外,您还可以免费获得所有spring security功能.
Spring security solves the problem description, and as a bonus you will get all the spring security features for free.
令牌方法很棒,这是您如何通过spring-security保护API的方法 实现AuthenticationEntryPoint,并设置了begin方法集401,而不是如下所述的重定向3XX
The Token approach is great and here is how you can secure your APIs with spring-security Implements AuthenticationEntryPoint and have the commence method set 401 instead of re-direction 3XX as follows
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Access Denied");
- 具有TokenProcessingFilter扩展并利用UsernamePasswordAuthenticationFilter必须提供的功能,重写doFilter()方法,从请求标头中提取令牌,按如下所示验证和验证令牌
@Override
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = this.getAsHttpRequest(request);
String authToken = this.extractAuthTokenFromRequest(httpRequest);
String userName = TokenUtils.getUserNameFromToken(authToken);
if (userName != null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
if (TokenUtils.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication =new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
您的Spring安全性配置如下
Your Spring-security configuration will look like
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthFailure authFailure;
@Autowired
private AuthSuccess authSuccess;
@Autowired
private EntryPointUnauthorizedHandler unauthorizedHandler;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationTokenProcessingFilter authTokenProcessingFilter;
@Autowired
public void configureAuthBuilder(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // Restful hence stateless
.and()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler) // Notice the entry point
.and()
.addFilter(authTokenProcessingFilter) // Notice the filter
.authorizeRequests()
.antMatchers("/resources/**", "/api/authenticate").permitAll()
//.antMatchers("/admin/**").hasRole("ADMIN")
//.antMatchers("/providers/**").hasRole("ADMIN")
.antMatchers("/persons").authenticated();
}
}
-最后,您将需要另一个端点进行身份验证和令牌生成 这是Spring MVC的例子
-- Last you will need another end point for Authentication and token-generation Here is a spring MVC example
@Controller
@RequestMapping(value="/api")
public class TokenGenerator{
@Autowired
@Lazy
private AuthenticationManager authenticationManager;
@Autowired
private UtilityBean utilityBean;
@Autowired
private UserDetailsService userDetailsService;
@RequestMapping(value="/authenticate", method=RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<?> generateToken(@RequestBody EmefanaUser user){
ResponseEntity<?> response = null;
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserId(),user.getCredential());
try {
Authentication authentication = authenticationManager.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
/*
* Reload user as password of authentication principal will be null
* after authorization and password is needed for token generation
*/
UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUserId());
String token = TokenUtils.createToken(userDetails);
response = ResponseEntity.ok(new TokenResource(utilityBean.encodePropertyValue(token)));
} catch (AuthenticationException e) {
response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
return response;
}
}
1生成令牌,2.后续的API调用应具有令牌 是的,春季安全性可以做到这一点,您不必在身份验证,授权方面开辟新天地.
1 Generate token, 2. subsequent API-calls should have the token Yes spring-security can do this and you don`t have to break new grounds in Authentication, Authorization.
- 希望这会有所帮助
这篇关于使用Liferay在REST服务中进行身份验证和授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!