当前位置: 首页 > 知识库问答 >
问题:

通过spring进行RESTful身份验证

郑俊弼
2023-03-14

问题:
我们有一个spring的基于MVC的RESTful API,它包含敏感信息。API应该是安全的,但是不希望在每个请求中发送用户的凭据(User/Pass组合)。根据REST指南(和内部业务需求),服务器必须保持无状态。API将由另一台服务器以混搭方式使用。

要求:

>

  • 客户端请求使用凭据.../authenticate(不受保护的URL);服务器返回一个安全令牌,该令牌包含足够的信息,供服务器验证未来的请求并保持无状态。这可能包含与spring安全公司的Remember-Me令牌相同的信息。

    客户端向各种(受保护的)URL发出后续请求,将先前获得的令牌附加为查询参数(或者,不太理想的情况下,附加为HTTP请求头)。

    不能期望客户端存储Cookie。

    既然我们已经使用了spring,解决方案就应该利用spring安全。

    我们一直在努力使这件事成功,所以希望有人已经解决了这个问题。

    考虑到上述情况,您如何解决这个特殊的需求?

  • 共有1个答案

    程谭三
    2023-03-14

    我们设法使其完全按照操作中的描述工作,希望其他人可以使用该解决方案。以下是我们所做的:

    设置安全上下文,如下所示:

    <security:http realm="Protected API" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="CustomAuthenticationEntryPoint">
        <security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
        <security:intercept-url pattern="/authenticate" access="permitAll"/>
        <security:intercept-url pattern="/**" access="isAuthenticated()" />
    </security:http>
    
    <bean id="CustomAuthenticationEntryPoint"
        class="com.demo.api.support.spring.CustomAuthenticationEntryPoint" />
    
    <bean id="authenticationTokenProcessingFilter"
        class="com.demo.api.support.spring.AuthenticationTokenProcessingFilter" >
        <constructor-arg ref="authenticationManager" />
    </bean>
    

    如您所见,我们创建了一个自定义的authenticationentrypoint,如果请求没有通过我们的authenticationtokenprocessingfilter在筛选器链中进行身份验证,它基本上只是返回一个401 unauthorized

    CustomAuthenticationEntryPoint:

    public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response,
                AuthenticationException authException) throws IOException, ServletException {
            response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Authentication token was either missing or invalid." );
        }
    }
    

    AuthenticationTokenProcessingFilter:

    public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
    
        @Autowired UserService userService;
        @Autowired TokenUtils tokenUtils;
        AuthenticationManager authManager;
    
        public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) {
            this.authManager = authManager;
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            @SuppressWarnings("unchecked")
            Map<String, String[]> parms = request.getParameterMap();
    
            if(parms.containsKey("token")) {
                String token = parms.get("token")[0]; // grab the first "token" parameter
    
                // validate the token
                if (tokenUtils.validate(token)) {
                    // determine the user based on the (already validated) token
                    UserDetails userDetails = tokenUtils.getUserFromToken(token);
                    // build an Authentication object with the user's info
                    UsernamePasswordAuthenticationToken authentication = 
                            new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request));
                    // set the authentication into the SecurityContext
                    SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(authentication));         
                }
            }
            // continue thru the filter chain
            chain.doFilter(request, response);
        }
    }
    

    很明显,tokenutils包含一些隐私(并且非常特定于大小写)的代码,不能很容易地共享。下面是它的界面:

    public interface TokenUtils {
        String getToken(UserDetails userDetails);
        String getToken(UserDetails userDetails, Long expiration);
        boolean validate(String token);
        UserDetails getUserFromToken(String token);
    }
    

    那应该能让你有一个好的开始。快乐编码。:)

     类似资料:
    • 问题内容: 问题: 我们有一个基于Spring MVC的RESTful API,其中包含敏感信息。该API应该是安全的,但是不希望随每个请求一起发送用户凭证(用户/密码组合)。根据REST准则(和内部业务要求),服务器必须保持无状态。该API将由另一台服务器以mashup方式使用。 要求: 客户端使用凭据向(不受保护的URL)发出请求;服务器返回一个安全令牌,该令牌包含足够的信息供服务器验证未来的

    • 我正在开发一个移动应用程序,服务器端是使用Spring3 MVC的REST。 我试图将Spring Security与它集成以保护资源。我通读了很多资料以获得如何做这件事的信息。我理解体系结构,但是,当涉及到实现时,我仍然感到困惑。 我提出了一个这样的问题;我也有同样的要求。我理解代码,但是,我对第一个身份验证请求何时到来感到困惑;那时,标记将不作为头的一部分出现,因此相同的过滤器将不起作用。 所

    • 在我使用RESTful webservices的Spring Boot应用程序中,我将Spring Security与Spring Social和一起配置了。 现在我有两种身份验证/授权方式--通过用户名/密码和通过社交网络,比如Twitter。 为了通过Spring MVC REST控制器中自己的RESTfulendpoint实现身份验证/授权,我添加了以下方法: 但我不确定在成功调用endpo

    • 我有一个react应用程序在一个单独的端口(localhost:3000)上运行,我想用它来验证用户,目前我的Spring后端(localhost:8080)有一个代理设置。 我能以某种方式手动验证而不是通过发送一个请求到我的后端,并获得一个会话cookie,然后在每个请求中包含cookie吗?这也将简化iOS方面的验证过程(使用此过程,我只能将会话cookie值存储在keychain中,并在每次

    • 问题内容: 在(带有)中,我尝试使用以下语句通过基本身份验证访问我的网页: 但是Google Chrome浏览器在控制台中向我发出以下警告: [弃用]其URL包含嵌入式凭据(例如https://user:pass@host/)的子资源请求被阻止。有关更多详细信息,请参见https://www.chromestatus.com/feature/5669008342777856。 在标记的链接中提到该

    • (我曾在SO上回顾过类似的问题,但没有一个建议对我有效) 我有一个API服务,运行在Google App Engine上(在Google云平台上)。我需要通过谷歌管理目录API的身份验证,以便我可以在我们的GSuite域上创建组。 我最初尝试了隐式授权,遵循指南,以手动获取和提供服务帐户凭据,但我认为这可能仅限于在Google App Engine上运行的应用程序之间的通信。我的理解是,在App