2

对于没有配置 SSL 的 URL,如何让 shiro 改回“http”?

目前,我的登录网址与 SSL 过滤器挂钩。

/登录 = ssl[8443],authc

当我登录时,它停留在 https,并且不会切换回 HTTP。

对于未经过 SslFilter'ized 的 URL,如何使其恢复为 HTTP?

4

1 回答 1

0

如果您使用表单身份验证,您可以通过扩展 FormAuthenticationFilter 并重定向到非 https URL 来自定义“登录时”行为。

这是一个例子:

package example.shiro;

import java.net.MalformedURLException;
import java.net.URL;

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

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authz.PortFilter;
import org.apache.shiro.web.filter.authz.SslFilter;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AuthenticatingFilter extends FormAuthenticationFilter {

    private static Logger logger = LoggerFactory.getLogger( AuthenticatingFilter.class );

    private int port = PortFilter.DEFAULT_HTTP_PORT;

    private String indexUrl = "/";

    public void setPort( int port ) {
        this.port = port;
    }

    public void setIndexUrl( String indexUrl ) {
        this.indexUrl = indexUrl;
    }

    @Override
    protected boolean onLoginSuccess( AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response ) throws Exception {
        boolean result = true;
        String reqScheme = request.getScheme();
        if( SslFilter.HTTPS_SCHEME.equals( reqScheme ) ) {
            HttpServletRequest httpReq = null;
            if( request instanceof HttpServletRequest ) {
                httpReq = WebUtils.toHttp( request );
                String uri;
                String query;
                SavedRequest savedRequest = WebUtils.getSavedRequest( request );
                if( savedRequest == null ) {
                    uri = httpReq.getRequestURI();
                    query = httpReq.getQueryString();
                }
                else {
                    uri = savedRequest.getRequestURI();
                    query = savedRequest.getQueryString();
                }
                String redirectUrl = fromHttps( httpReq, uri, query );
                WebUtils.issueRedirect( request, response, redirectUrl, null, false );
                result = false;
            }
            else {
                if( logger.isWarnEnabled() ) {
                    logger.warn( "request is not an instance of HttpServletRequest: {}", request.getClass().toString() );
                }
                result = true;
            }
        }
        else {
            result = super.onLoginSuccess( token, subject, request, response );
        }
        return result;
    }

    private String fromHttps( HttpServletRequest request, String uri, String query ) {
        StringBuilder sb = new StringBuilder();
        try {
            URL originalURL = new URL( request.getRequestURL().toString() );
            sb.append( PortFilter.HTTP_SCHEME );
            sb.append( "://" );
            sb.append( originalURL.getHost() );
            if( originalURL.getPort() != port && port != PortFilter.DEFAULT_HTTP_PORT ) {
                sb.append( ":" );
                sb.append( port );
            }
            String path = originalURL.getPath();
            int semiPos = path.indexOf( ";" ); // if there was pathParameter data it should have been on the original request, it sometimes seems be missing from request.getPathInfo()?
            String pathParameters = "";
            if( semiPos > 0 ) {
                pathParameters = path.substring( semiPos );
            }
            semiPos = uri.indexOf( ";" ); // pathParameter data may be present on uri (from a saved request), if so, throw it away as it may be from a bookmark
            if( semiPos > 0 ) {
                uri = uri.substring( 0, semiPos );
            }
            if( uri.endsWith( getLoginUrl() ) ) {
                int loginPos = uri.indexOf( getLoginUrl() );
                String contextPath = uri.substring( 0, loginPos );
                sb.append( contextPath );
                sb.append( indexUrl );
            }
            else {
                sb.append( uri );
            }
            sb.append( pathParameters );
            if( query != null ) {
                sb.append( "?" ).append( query );
            }
            if( logger.isTraceEnabled() ) {
                logger.trace( "redirect url is : {}", sb.toString() );
            }
        }
        catch( MalformedURLException e ) {
            logger.error( "cannot construct request URL", e );
        }
        return sb.toString();
    }

}

您还需要 shiro.ini 中的一些相应条目:

[main]       
authc = example.shiro.AuthenticatingFilter
authc.loginUrl = /somepath/login
authc.port = 8080
authc.indexUrl = /somepath/index

[urls]
/somepath/index = anon
/somepath/login = ssl[8443], authc

这个提议的解决方案远非完美,但可以在我正在使用的堆栈中完成工作(shiro、jersey、tomcat),如果你能找到更好和/或更通用的解决方法,请分享它!

干杯,

JJB

于 2012-12-28T16:31:46.693 回答