使用 Liferay 在 REST 服务中进行身份验证和授权 [英] Authentication and authorization in REST Services with Liferay

查看:54
本文介绍了使用 Liferay 在 REST 服务中进行身份验证和授权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在构建一些将通过 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 的应用程序.

我们的设计是:

  1. 当用户登录我们的门户时,Liferay 会创建一个带有 userLogin(或 ID)+ 客户端 IP + 时间戳的身份验证令牌.此令牌保存在 cookie 中;
  2. 在每次 REST 调用之前,Angular 会读取此 cookie 并通过 HTTP 标头发送其内容;
  3. 我们的服务会解密"发送的 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.

菲利普

推荐答案

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 并将开始方法设置为 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

    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-security 配置看起来像

    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 调用应具有令牌是的,spring-security 可以做到这一点,而且您不必在身份验证、授权方面开辟新天地.

    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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆