java - shiro 中的 SslFilter 不会重定向回 http

标签 java shiro

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

目前,我的登录 URL 与 SSL 过滤器 Hook 。

/login = ssl[8443],authc

当我登录时,它停留在 https,并没有切换回 HTTP。

对于未经过 SslFilter 处理的 URL,我如何让它恢复为 HTTP?

最佳答案

如果您使用表单例份验证,您可以通过扩展 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

关于java - shiro 中的 SslFilter 不会重定向回 http,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13950900/

相关文章:

Java - 获取对象的arrayList中最常见的元素

java - 如何在一个 JAR 中实现多个 SPI

ldap - Shiro JndiLdapRealm 针对 LDAP 的授权

java - 配置 Hazelcast 和 Shiro

java - Hibernate/HQL - 如何获取从数据库返回的所有重复项?

java - Android 应用中的 Admob 广告问题

java - Collections.sort 错误 : no suitable method found for sort

grails - 如何使用 shiro 在 grails 中显示用户的名字

java - Apache ·希罗. WebUtils.isWeb(...) 和 WebUtils.isHttp(...) 有什么区别?

java - shiro 在身份验证 web 应用程序上按角色重定向