json - Spring Security 和 JSON 身份验证

我在 spring/spring-mvc 中有一个完全使用 JSON 通信的应用程序。 现在我需要通过 JSON 使用 spring security 3(使用 LdapAuthenticationProvider)对我的应用程序进行身份验证。

默认的 spring 安全提交表单需要这样的 POST:

POST /myapp/j_spring_security_check HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 32
Host: 127.0.0.1:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

j_username=myUsername&j_password=myPass

但我想像这样传递一个 JSON 对象:

{"j_username":"myUsername","j_password":"myPass"}

我读过很多帖子,例如 this , this other或 this one没有运气,在所有 ajax 情况下都是像上面那样做一个 POST。

有什么想法吗?

最佳答案

根据凯文的建议,
并在阅读此帖子后:1 , 2 , 文档 3 ,感谢 this博文,
我自己写了FORM_LOGIN_FILTER,在认证前直接管理JSON。
我将我的代码粘贴到社区。​​p>

目标是同时授予经典浏览器表单 POST 身份验证和基于 JSON 的身份验证。同样在 JSON 身份验证中,我想避免重定向到 loginSuccesful.htm

在上下文中:

<security:http use-expressions="true" auto-config="false" entry-point-ref="http403EntryPoint">      
    <security:intercept-url pattern="/logs/**" access="denyAll" />
    <!-- ... All other intercept URL -->

    <security:custom-filter ref="CustomUsernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER "/>
    <security:logout
            invalidate-session="true"
            logout-success-url="/LogoutSuccessful.htm"
            delete-cookies="true"
    />
    <security:session-management>
        <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
    </security:session-management>
    <security:access-denied-handler error-page="/accessDenied.htm" />
</security:http>

<bean id="CustomUsernamePasswordAuthenticationFilter" class="path.to.CustomUsernamePasswordAuthenticationFilter">
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="authenticationSuccessHandler" ref="customSuccessHandler"/>
    <property name="authenticationFailureHandler" ref="failureHandler"/>
    <property name="filterProcessesUrl" value="/j_spring_security_check"/>
    <property name="usernameParameter" value="j_username"/>
    <property name="passwordParameter" value="j_password"/>
</bean>

<bean id="customSuccessHandler" class="path.to.CustomAuthenticationSuccessHandler">
    <property name="defaultTargetUrl" value="/login.htm" />
    <property name="targetUrlParameter" value="/LoginSuccessful.htm" />
</bean>

<bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
    <property name="defaultFailureUrl" value="/login.htm" />
</bean>

<bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />

CustomUsernamePasswordAuthenticationFilter 类:

public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{
    private String jsonUsername;
    private String jsonPassword;

    @Override
    protected String obtainPassword(HttpServletRequest request) {
        String password = null; 

        if ("application/json".equals(request.getHeader("Content-Type"))) {
            password = this.jsonPassword;
        }else{
            password = super.obtainPassword(request);
        }

        return password;
    }

    @Override
    protected String obtainUsername(HttpServletRequest request){
        String username = null;

        if ("application/json".equals(request.getHeader("Content-Type"))) {
            username = this.jsonUsername;
        }else{
            username = super.obtainUsername(request);
        }

        return username;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
        if ("application/json".equals(request.getHeader("Content-Type"))) {
            try {
                /*
                 * HttpServletRequest can be read only once
                 */
                StringBuffer sb = new StringBuffer();
                String line = null;

                BufferedReader reader = request.getReader();
                while ((line = reader.readLine()) != null){
                    sb.append(line);
                }

                //json transformation
                ObjectMapper mapper = new ObjectMapper();
                LoginRequest loginRequest = mapper.readValue(sb.toString(), LoginRequest.class);

                this.jsonUsername = loginRequest.getUsername();
                this.jsonPassword = loginRequest.getPassword();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return super.attemptAuthentication(request, response);
    }
}

CustomAuthenticationSuccessHandler 类:

public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    public void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication auth
    )throws IOException, ServletException {

        if ("application/json".equals(request.getHeader("Content-Type"))) {
            /*
             * USED if you want to AVOID redirect to LoginSuccessful.htm in JSON authentication
             */         
            response.getWriter().print("{\"responseCode\":\"SUCCESS\"}");
            response.getWriter().flush();
        } else {
            super.onAuthenticationSuccess(request, response, auth);
        }
    }
}

https://stackoverflow.com/questions/19500332/

相关文章:

php - 在 JSON 编码的 HTML5 数据属性中转义/编码单引号

java - 从 json 文本文件加载 JSONObject 的最佳方法是什么?

jquery - 将序列化表单的数据转换为 json 对象

java - JSON键是否需要唯一?

java - Spring 3.2 测试,com.jajway 不包含在依赖项中

json - 如何配置spring mvc 3在json响应中不返回 "null"对象?

javascript - Socket.io 如何发送 JavaScript 对象

javascript - 使用来自 JSON 数据的不同值,而不是使用 Typeahead 的 di

javascript - 使用带有 javascript 的对象使用 JSON 数组

json - 如何在 Perl 中将简单的哈希转换为 json?