spring security 导致 spring mvc 绑定数据乱码

症状:

项目使用了spring mvc 和 spring security ,直接浏览器地址栏敲击请求,导致control中数据绑定到对象乱码。

使用 request.getParameter(name) 编码正确,request.getParameterValues(name) 乱码

经查org.springframework.web.bind.ServletRequestDataBinder.bind() 方法

MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);

结果已为乱码

org.springframework.web.util.WebUtils.getParametersStartingWith 中进行了request数据的获取封装,但是request已经被spring security封装为org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper,见代码org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(),水土不服的spring security 已经让我纠结到是不是自己写权限框架的地步了。

对症下药:

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;

public class I18NSecurityContextHolderAwareRequestFilter extends GenericFilterBean {
	 //~ Instance fields ================================================================================================

    private String rolePrefix;

    //~ Methods ========================================================================================================

    public void setRolePrefix(String rolePrefix) {
        Assert.notNull(rolePrefix, "Role prefix must not be null");  
        this.rolePrefix = rolePrefix.trim();
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        chain.doFilter(new I18NSecurityContextHolderAwareRequestWrapper((HttpServletRequest) req, rolePrefix), res);
    }
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import java.security.Principal;
import java.util.Collection;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import com.emagsoftware.web.session.SessionHttpServletRequestWrapper;


/**
* A Spring Security-aware <code>HttpServletRequestWrapper</code>, which uses the
* <code>SecurityContext</code>-defined <code>Authentication</code> object to implement the servlet API security
* methods {@link SecurityContextHolderAwareRequestWrapper#isUserInRole(String)} and {@link
* HttpServletRequestWrapper#getRemoteUser()}.
*
* @see SecurityContextHolderAwareRequestFilter
*
* @author Orlando Garcia Carmona
* @author Ben Alex
* @author Luke Taylor
*/
public class I18NSecurityContextHolderAwareRequestWrapper extends SessionHttpServletRequestWrapper {
   //~ Instance fields ================================================================================================

   private final AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();

   /**
    * The prefix passed by the filter. It will be prepended to any supplied role values before
    * comparing it with the roles obtained from the security context.
    */
   private final String rolePrefix;
   private static String charset = "utf-8";
   
   //~ Constructors ===================================================================================================

   public I18NSecurityContextHolderAwareRequestWrapper(HttpServletRequest request, String rolePrefix) {
       super(request,charset);
       this.rolePrefix = rolePrefix;
   }

   //~ Methods ========================================================================================================

   /**
    * Obtain the current active <code>Authentication</code>
    *
    * @return the authentication object or <code>null</code>
    */
   private Authentication getAuthentication() {
       Authentication auth = SecurityContextHolder.getContext().getAuthentication();

       if (!authenticationTrustResolver.isAnonymous(auth)) {
           return auth;
       }

       return null;
   }

   /**
    * Returns the principal's name, as obtained from the <code>SecurityContextHolder</code>. Properly handles
    * both <code>String</code>-based and <code>UserDetails</code>-based principals.
    *
    * @return the username or <code>null</code> if unavailable
    */
   @Override
   public String getRemoteUser() {
       Authentication auth = getAuthentication();

       if ((auth == null) || (auth.getPrincipal() == null)) {
           return null;
       }

       if (auth.getPrincipal() instanceof UserDetails) {
           return ((UserDetails) auth.getPrincipal()).getUsername();
       }

       return auth.getPrincipal().toString();
   }

   /**
    * Returns the <code>Authentication</code> (which is a subclass of <code>Principal</code>), or
    * <code>null</code> if unavailable.
    *
    * @return the <code>Authentication</code>, or <code>null</code>
    */
   @Override
   public Principal getUserPrincipal() {
       Authentication auth = getAuthentication();

       if ((auth == null) || (auth.getPrincipal() == null)) {
           return null;
       }

       return auth;
   }

   private boolean isGranted(String role) {
       Authentication auth = getAuthentication();

       if( rolePrefix != null ) {
           role = rolePrefix + role;
       }

       if ((auth == null) || (auth.getPrincipal() == null)) {
           return false;
       }

       Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();

       if (authorities == null) {
           return false;
       }


       for (GrantedAuthority grantedAuthority : authorities) {
           if (role.equals(grantedAuthority.getAuthority())) {
               return true;
           }
       }

       return false;
   }

   /**
    * Simple searches for an exactly matching {@link org.springframework.security.core.GrantedAuthority#getAuthority()}.
    * <p>
    * Will always return <code>false</code> if the <code>SecurityContextHolder</code> contains an
    * <code>Authentication</code> with <code>null</code><code>principal</code> and/or <code>GrantedAuthority[]</code>
    * objects.
    *
    * @param role the <code>GrantedAuthority</code><code>String</code> representation to check for
    *
    * @return <code>true</code> if an <b>exact</b> (case sensitive) matching granted authority is located,
    *         <code>false</code> otherwise
    */
   @Override
   public boolean isUserInRole(String role) {
       return isGranted(role);
   }

   @Override
   public String toString() {
       return "SecurityContextHolderAwareRequestWrapper[ " + getRequest() + "]";
   }
}
    <custom-filter before="securityContextHolderAwareRequestFilte" ref="securityContextHolderAwareRequestFilte"/>
    <b:bean id="securityContextHolderAwareRequestFilte" class="com.ff.ffservice.mvc.rule.I18NSecurityContextHolderAwareRequestFilter"/>
public class SessionHttpServletRequestWrapper extends HttpServletRequestWrapper
	private String charset = "UTF-8";
        /**
	 * 实际上就是调用被包装的请求对象的getParameter方法获得参数,然后再进行编码转换
	 */
	public String getParameter(String name) {
		String value = super.getParameter(name);
		if ("get".equalsIgnoreCase(super.getMethod())) {
			value = value == null ? null : convert(value);
		}
		return value;
	}

	private HttpServletRequest getHttpServletRequest() {
		return (HttpServletRequest) super.getRequest();
	}

	// 重写获得一组表单数据方法
	// @param arg0 请求参数
	public String[] getParameterValues(String arg0) {
		// 请求内容类型字符串
		String contentType = getHttpServletRequest().getContentType();
		// 上传组件
		if (contentType != null
				&& contentType.indexOf("multipart/form-data") != -1) {
			return getHttpServletRequest().getParameterValues(arg0);
		} else {// 普通提交
			String values[] = getHttpServletRequest().getParameterValues(arg0);
			if (values != null) {
				for (int i = 0; i < values.length; i++) {
					values[i] = convert(values[i]);
				}
			}
			return values;
		}
	}

	public String convert(String target) {
		try {
			return new String(target.trim().getBytes("ISO-8859-1"), charset);
		} catch (UnsupportedEncodingException e) {
			return target;
		}
	}
}


你可能感兴趣的:(spring security 导致 spring mvc 绑定数据乱码)