具有自定义提供程序+注销的Spring Security OAuth2 SSO

时间:2015-12-20 09:14:04

标签: spring-security spring-boot single-sign-on spring-security-oauth2

我正在尝试使用Spring-boot和Dave Syer样本实现Spring Security Oauth2的sso

我想使用我的custom server提供商并且工作正常。

对于客户端,我希望用户在尝试访问客户端站点(例如localhost:8080 /)时进行身份验证(因此重定向到OAuth2 url),并在进行身份验证后重定向回index.html文件。我还想在用户访问index.html文件中的链接时实现注销。

我已经提出了以下客户端sso客户端:

package org.ikane;

import java.io.IOException;
import java.security.Principal;
import java.util.Arrays;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;

@SpringBootApplication
@Controller
public class DemoSsoOauth2ClientApplication implements CommandLineRunner {

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

    @Override
    public void run(String... arg0) throws Exception {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        try {
            Authentication authentication = securityContext.getAuthentication();
            logger.info(authentication.getDetails().toString());

            SecurityContextHolder.clearContext();
        } catch (Exception e) {
            logger.error("Error", e);
        }
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoSsoOauth2ClientApplication.class, args);
        ConfigurableEnvironment env = applicationContext.getEnvironment();
        logger.info("\n\thttp://localhost:{}{}\n\tProfiles:{}\n", 
                StringUtils.defaultIfEmpty(env.getProperty("server.port"), "8080"), 
                StringUtils.defaultIfEmpty(env.getProperty("server.contextPath"), "/"),
                Arrays.toString(env.getActiveProfiles()));
    }

    @RequestMapping(value="/")
    public String home() {
        return "index";
    }

    @RequestMapping(value="/user")
    @ResponseBody
    public Principal user(Principal user) {
        return user;
    }

    /**
     * The Class OAuthConfiguration that sets up the OAuth2 single sign on
     * configuration and the web security associated with it.
     */
    @Component
    @Controller
    @EnableOAuth2Sso
    protected static class OAuthClientConfiguration extends WebSecurityConfigurerAdapter {

        private static final String CSRF_COOKIE_NAME = "XSRF-TOKEN";
        private static final String CSRF_ANGULAR_HEADER_NAME = "X-XSRF-TOKEN";

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/**").authorizeRequests()
                    .antMatchers("/index.html", "/").permitAll().anyRequest()
                    .authenticated().and().csrf().csrfTokenRepository(csrfTokenRepository())
                    .and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
        }

        private Filter csrfHeaderFilter() {
            return new OncePerRequestFilter() {

                @Override
                protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                        throws ServletException, IOException {
                    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
                    if (csrf != null) {
                        Cookie cookie = WebUtils.getCookie(request, CSRF_COOKIE_NAME);
                        String token = csrf.getToken();
                        if (cookie == null || token != null
                                && !token.equals(cookie.getValue())) {
                            cookie = new Cookie(CSRF_COOKIE_NAME, token);
                            cookie.setPath("/");
                            response.addCookie(cookie);
                        }
                    }
                    filterChain.doFilter(request, response);
                }
            };
        }

        /**
         * Angular sends the CSRF token in a custom header named "X-XSRF-TOKEN"
         * rather than the default "X-CSRF-TOKEN" that Spring security expects.
         * Hence we are now telling Spring security to expect the token in the
         * "X-XSRF-TOKEN" header.

* * This customization is added to the csrf() filter. * * @return */ private CsrfTokenRepository csrfTokenRepository() { HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); repository.setHeaderName(CSRF_ANGULAR_HEADER_NAME); return repository; } } }

您可以找到GitHub source。有关如何实现此用例的任何提示?

提前致谢

1 个答案:

答案 0 :(得分:2)

  • 要使您的客户端应用程序重定向到授权服务器,只需添加即可 @EnableOAuth2SsoWebSecurityConfigurerAdapter上的注释C:\Anaconda3 在您的属性文件中放置正确的OAuth2配置(client-id,secret,access token uri ...)。 (我假设您的客户端应用程序也使用Spring Boot)

  • 要结束用户的会话,您必须重定向到授权服务器中的端点并以编程方式注销,如this post所示。

我创建了一个repository on github,其中包含一个示例应用,其中包含您正在寻找的功能。

请检查一下,如果有帮助,请告诉我。