如何处理多个身份验证 [英] How to handle multiple Authenticator

查看:120
本文介绍了如何处理多个身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要验证的请求,我用 Authenticator.setDefault 这是虚拟机宽...
如果我想区分不同的Web服务 而且每一个都清楚自己的身份验证凭据。
我需要 Authenticator.setDefault 为每个请求?
如果有混合web服务的并发连接,这可能无法正常工作......

To authenticate a request, I use Authenticator.setDefault which is VM wide...
What If I want to separate different webservices and each one are aware of their authentication credentials.
Do I need to Authenticator.setDefault for each request ?
This may not work if there are concurrent connection with mixed webservices...

推荐答案

建立在迈克的回应上面我有以下的解决方案,因为当我还是AP preciate的总体思路(这就是为什么我把它复制; - ),我看到了一些问题吧:

Building on Mike's response above I have the following solution, because while I much appreciate the general idea (that's why I've copied it ;-) , I see a few problems with it:

  • 在迈克的解决方案将抛出NullPointerException如果JDK通过在java.net.Authenticator中的两个静态请求方法不通过URL一部申请认证(当时getRequestingURL()将返回null)。
  • 它要求你通过在解构URL外部正则表达式。这是(很)容易得到错误的,并在JDK中的URL类实现此分析,所以我preFER使用的。
  • 在它需要一些外部类构建的PasswordAut​​hentication对象的地图,然后将其设置。它不实现,在系统的其他组件可以使用注册机制。我也把它变成一个单例。
  • 更多的风格件事:我不建议重复类名(验证),所以我给它改名DefaultAuthenticator

下面的解决方案,我认为解决这些问题。

Below solution I think solves these issues.

    /**
     * Authenticator which keeps credentials to be passed to the requestor based on authority of the requesting URL. The
     * authority is <pre>user:password@host:port</pre>, where all parts are optional except the host.
     * <p>
     * If the configured credentials are not found, the Authenticator will use the credentials embedded in the URL, if
     * present. Embedded credentials are in the form of <pre>user:password@host:port</pre>
     *   
     * @author Michael Fortin 2011-09-23
     */
    public final class DefaultAuthenticator extends Authenticator {

        private static final Logger LOG = Logger.getLogger(DefaultAuthenticator.class.getName());
        private static DefaultAuthenticator instance;

        private Map<String, PasswordAuthentication> authInfo = new HashMap<String, PasswordAuthentication>();

        private DefaultAuthenticator() {
        }

        public static synchronized DefaultAuthenticator getInstance() {
            if (instance == null) {
                instance = new DefaultAuthenticator();
                Authenticator.setDefault(instance);
            }
            return instance;
        }

        // unit testing
        static void reset() {
            instance = null;
            Authenticator.setDefault(null);        
        }

        @Override
        protected PasswordAuthentication getPasswordAuthentication() {

            String requestorInfo = getRequestorInfo();
            LOG.info(getRequestorType() + " at \"" + getRequestingPrompt() + "\" is requesting " + getRequestingScheme()
                    + " password authentication for \"" + requestorInfo + "\"");

            if (authInfo.containsKey(requestorInfo)) {
                return authInfo.get(requestorInfo);
            } else {
                PasswordAuthentication pa = getEmbeddedCredentials(getRequestingURL());
                if (pa == null) {
                    LOG.warning("No authentication information");
                }
                return pa;
            }

        }

        /**
         * Register the authentication information for a given URL.
         * 
         * @param url - the URL that will request authorization
         * @param auth - the {@link PasswordAuthentication} for this URL providing the credentials
         */
        public void register(URL url, PasswordAuthentication auth) {
            String requestorInfo = getRequestorInfo(url.getHost(), url.getPort()); 
            authInfo.put(requestorInfo, auth);
        }

        /**
         * Get the requestor info based on info provided.
         * 
         * @param host - hostname of requestor
         * @param port - TCP/IP port
         * @return requestor info string
         */
        private String getRequestorInfo(String host, int port) {

            String fullHostname;
            try {
                InetAddress addr = InetAddress.getByName(host);
                fullHostname = addr.getCanonicalHostName();
            } catch (UnknownHostException e) {
                fullHostname = host;
            }

            if (port == -1) {
                return fullHostname;
            } else {
                return fullHostname + ":" + port;
            }
        }

        /**
         * Get the requestor info for the request currently being processed by this Authenticator.
         * 
         * @return requestor info string for current request
         */
        private String getRequestorInfo() {

            String host;
            InetAddress addr = getRequestingSite();
            if (addr == null) {
                host = getRequestingHost();
            } else {
                host = addr.getCanonicalHostName();
            }
            return getRequestorInfo(host, getRequestingPort());
        }

        /**
         * Get the credentials from the requesting URL.
         * 
         * @param url - URL to get the credentials from (can be null, method will return null)
         * @return PasswordAuthentication with credentials from URL or null if URL contains no credentials or if URL is
         * null itself
         */
        PasswordAuthentication getEmbeddedCredentials(URL url) {

            if (url == null) {
                return null;
            }

            String userInfo = url.getUserInfo();
            int colon = userInfo == null ? -1 : userInfo.indexOf(":");
            if (colon == -1) {
                return null;
            } else {
                String userName = userInfo.substring(0, colon);
                String pass = userInfo.substring(colon + 1);
                return new PasswordAuthentication(userName, pass.toCharArray());
            }
        }
    }

虽然我吧,让我给你我的单元测试(JUnit 4中)。

While I'm at it, let me give you my unit tests (JUnit 4).

    /**
     * @author Paul Balm - May 10 2012
     */
    public class DefaultAuthenticatorTest {

        private static final Logger LOG = Logger.getLogger(DefaultAuthenticatorTest.class.getName());

        @Before
        public void setUp() throws Exception {
            DefaultAuthenticator.reset();
            DefaultAuthenticator.getInstance();
        }

        @After
        public void tearDown() {
            DefaultAuthenticator.reset();
        }

        @Test
        public void testRequestAuthenticationFromURL() throws MalformedURLException, UnknownHostException {

            Map<String, String[]> urls = generateURLs();

            for (String urlStr : urls.keySet()) {
                String[] userInfo = urls.get(urlStr);
                LOG.info("Testing: " + urlStr);
                URL url = new URL(urlStr);
                request(userInfo[1], userInfo[2], url, true);
            }

        }

        @Test
        public void testRequestAuthenticationRegistered() throws UnknownHostException, MalformedURLException {

            Map<String, String[]> urls = generateURLs();

            for (String urlStr : urls.keySet()) {
                String[] userInfo = urls.get(urlStr);
                LOG.info("Testing: " + urlStr);
                URL url = new URL(urlStr);

                DefaultAuthenticator.reset();
                DefaultAuthenticator auth = DefaultAuthenticator.getInstance();

                String userName = userInfo[1];
                String password = userInfo[2];

                if (password != null) {
                    // You can't register a null password
                    auth.register(url, new PasswordAuthentication(userName, password.toCharArray()));
                }

                request(userName, password, url, false);
            }

        }

        /**
         *  Generate a bunch of URLs mapped to String array. The String array has the following elements:
         *  - user info part of URL, 
         *  - expected user, 
         *  - expected password
         *  
         *  Note that the keys of the maps must be strings and not URL objects, because of the way URL.equals is
         *  implemented. This method does not consider the credentials.
         *  
         * @throws MalformedURLException 
         */
        Map<String, String[]> generateURLs() {
            String[] hosts = new String[]{ "127.0.0.1", "localhost.localdomain"};

            List<String[]> userData = new ArrayList<String[]>();

            // normal cases
            userData.add(new String[] { "user:pass@", "user", "pass" }); // results in: http://user:pass@[host]
            userData.add(new String[] { "", null, null });
            // unexpected cases
            userData.add(new String[] { "@", null, null });
            userData.add(new String[] { ":@", "", "" });
            userData.add(new String[] { "user:@", "user", "" });
            userData.add(new String[] { ":pass@", "", "pass" });

            Map<String, String[]> urls = new HashMap<String, String[]>();

            for (String[] userInfo : userData) {
                for (String host : hosts) {
                    String s = "http://" + userInfo[0] + host;
                    urls.put(s, userInfo);
                }
            }

            LOG.info("" + urls.size() + " URLs prepared");

            return urls;
        }

        private void request(String expectedUser, String expectedPass, URL url, boolean inURL)
        throws UnknownHostException {        

            String host = url.getHost();
            InetAddress addr = InetAddress.getAllByName(host)[0];
            int port = url.getPort();
            String protocol = url.getProtocol();
            String prompt = ""; // prompt for the user when asking for the credentials
            String scheme = "basic"; // or digest
            RequestorType reqType = RequestorType.SERVER;

            PasswordAuthentication credentials =
                Authenticator.requestPasswordAuthentication(addr, port, protocol, prompt, scheme);
            // If the credentials are in the URL, you can't find them using this method because we're not passing the URL
            checkCredentials(url, inURL ? null : expectedUser, inURL ? null : expectedPass, credentials); 

            credentials = Authenticator.requestPasswordAuthentication(host, addr, port, protocol, prompt, scheme);
            // If the credentials are in the URL, you can't find them using this method because we're not passing the URL
            checkCredentials(url, inURL ? null : expectedUser, inURL ? null : expectedPass, credentials); 

            credentials = Authenticator.requestPasswordAuthentication(host, addr, port, protocol, prompt, scheme, url, reqType);
            checkCredentials(url, expectedUser, expectedPass, credentials);
        }

        private void checkCredentials(URL url, String expectedUser, String expectedPass, PasswordAuthentication credentials) {
            if (expectedUser == null) {
                Assert.assertNull(url.toString(), credentials);
            } else {
                Assert.assertNotNull(url.toString(), credentials);
                Assert.assertEquals(url.toString(), expectedUser, credentials.getUserName());

                if (expectedPass == null) {
                    Assert.assertNull(url.toString(), credentials.getPassword());
                } else {
                    Assert.assertArrayEquals(url.toString(), expectedPass.toCharArray(), credentials.getPassword());
                }
            }
        }

    }

这篇关于如何处理多个身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆