Spring Security 4 - REST身份验证失败和控制器异常处理程序

时间:2015-11-06 10:16:45

标签: java rest spring-mvc spring-security

我通过一些示例应用程序学习Spring Security。我遇到了一些问题。

我使用Spring 4.2.2.RELEASE 和Spring Security 4.0.2.RELEASE 。 这是我的Spring Security Context。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <context:component-scan base-package="com.mvc.sslspring.security" />

    <security:authentication-manager id="authenticationManager">
        <security:authentication-provider>
            <security:user-service>
                <security:user name="aa" password="aa" authorities="ROLE_USER" />
                <security:user name="bb" password="bb"
                    authorities="ROLE_USER, ROLE_ADMIN" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>

    <security:http realm="Protected API" use-expressions="true"
        auto-config="false" create-session="stateless" entry-point-ref="restAuthenticationEntryPoint"
        authentication-manager-ref="authenticationManager">

        <security:custom-filter ref="restAuthenticationTokenProcessingFilter"
            position="FORM_LOGIN_FILTER" />
        <security:intercept-url pattern="/authenticate" 
            access="permitAll" />

        <security:intercept-url pattern="/persons"
            access="isAuthenticated() and hasRole('ROLE_ADMIN')" />
        <security:intercept-url pattern="/persons/*"
            access="isAuthenticated() and hasRole('ROLE_ADMIN')" />
        <security:intercept-url pattern="/tasks"
            access="isAuthenticated() and hasRole('ROLE_USER')" />
        <security:intercept-url pattern="/tasks/*"
            access="isAuthenticated() and hasRole('ROLE_USER')" />

        <security:access-denied-handler ref="restAccessDeniedHandler" />

        <security:csrf disabled="true" />
    </security:http>
</beans>

(我已经禁用了CSRF,因为它给POSTMAN客户端带来了一些问题。) 当用户输入用户名和密码并发送s JSON并在标头中使用该标记时,我正在创建令牌,我正在访问资源。它对我来说很好,包括角色,除了很少的东西。

这是我的处理程序。

身份验证入口点处理程序

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
//      response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter out = response.getWriter();
        out.print("{\"message\":\""+ authException.getMessage() + "\", \"access-denied\":true,\"cause\":\"SC_UNAUTHORIZED\"}");
        out.flush();
        out.close();
    }
}

访问被拒绝处理程序

@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
            AccessDeniedException accessDeniedException) throws IOException, ServletException {
        // response.sendError(HttpServletResponse.SC_FORBIDDEN,
        // accessDeniedException.getMessage());
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        PrintWriter out = response.getWriter();
        out.print("{\"message\":\"" + accessDeniedException.getMessage()
                + "\", \"access-denied\":true,\"cause\":\"SC_FORBIDDEN\"}");
        out.flush();
        out.close();

    }
}

我的任务和人员控制器很少,而且它运行良好并返回JSON。

首先我对用户的身份验证有疑问。

这是控制器中的身份验证方法

@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
    public String authenticate(@RequestBody User user, HttpServletRequest request) throws Exception {

        UserDetails userDetails = userService.loadUserByUsername(user.getUsername());
        String tokenString = TokenUtils.createToken(user);
        return tokenString;
    }

User.java

import java.util.Collection;
import java.util.Collections;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class User implements UserDetails {

    private String username;
    private String password;

    // getters and setters
    // overridden methods
}

如果我输入正确的用户名和错误的密码,它就会创建并返回令牌。如果我输入错误的用户名,它将转到 RestAuthenticationEntryPoint 并使用JSON消息发回401错误。

如何使用配置文件中的用户名和密码对控制器方法中的用户进行身份验证?如果凭据错误,它应该使用自定义JSON发送401状态。

如果在任何控制器中发生任何异常,我应该能够使用JSON消息发送500错误。是否有任何常见的方法来发送错误响应并处理身份验证?

我知道可以有身份验证失败处理程序。但是在XML配置中,哪里提到它。除<security:form login/>之外,我没有看到该选项,但我没有使用它。

1 个答案:

答案 0 :(得分:1)

关于authenticate user in controller method with username and password的问题的答案。在控制器中,您使用自己的方法来获取用户身份验证详细信息,您无法使用配置文件中的用户凭据来执行此操作。因为您没有使用spring证券默认过滤器链。您可以使用默认设置来填充数据库中的用户或更改loadByUserName的实现以对这些用户进行硬编码。