Spring无法配置授权服务器

时间:2017-03-17 22:17:01

标签: java spring spring-boot spring-security spring-security-oauth2

我创建了一个简单的授权服务器,但无法对其进行配置。

  1. 启动两个应用程序(8080用于auth服务器,9999用于客户端)。
  2. 转到localhost:9999/client并重定向到localhost:8080/login(按预期方式)。
  3. 使用 user / user 填写登录表单。
  4. 重定向到localhost:9999/client(按预期方式),但Hello, null代替Hello, user
  5. 但是,如果我直接转到localhost:8080/me,我会{"name":"user"}。如何检索Hello, user

    授权服务器

    @RestController
    @EnableAuthorizationServer
    @SpringBootApplication
    public class Application extends WebSecurityConfigurerAdapter {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
        @GetMapping({ "/user", "/me" })
        public Map<String, String> user(Principal principal) {
            return Collections.singletonMap("name", principal == null ? "null" : principal.getName());
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("user").password("user").authorities(AuthorityUtils.NO_AUTHORITIES);
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin();
        }
    }
    

    应用程序的属性

    security:
      oauth2:
        client:
          client-id: clientid
          client-secret: clientsecret
          scope: read,write
          auto-approve-scopes: '.*'
    

    客户端

    @Configuration
    @EnableAutoConfiguration
    @EnableOAuth2Sso
    @RestController
    public class Client {
    
        @GetMapping("/")
        public String home(Principal principal) {
            return "Hello, " + principal.getName();
        }
    
        public static void main(String[] args) {
            new SpringApplicationBuilder(Client.class)
                    .properties("spring.config.name=client").run(args);
        }
    
    }
    

    客户的属性

    server:
      port: 9999
      context-path: /client
    security:
      oauth2:
        client:
          client-id: clientid
          client-secret: clientsecret
          access-token-uri: http://localhost:8080/oauth/token
          user-authorization-uri: http://localhost:8080/oauth/authorize
        resource:
          user-info-uri: http://localhost:8080/me
    

    更新
    我完成所有工作后都下载了a tutorial,但它只有ssoFilter,仅适用于OAuth2身份验证。我只想用loginForm配置它 我还在GitHub上分享了一个临时的example。我认为用它来查找问题会更容易。

4 个答案:

答案 0 :(得分:1)

有不同的端口 9999 8080 这会在从其他域请求资源时导致跨源 HTTP请求,或端口,而不是第一个资源本身所服务的端口。

有关 HTTP access control (CORS)

的详细信息

官方春季网站上有一个很好的例子Enabling Cross Origin Requests for a RESTful Web Service

我建议您只需通过实施Filter界面即可在您的应用上进行CORS过滤。

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    public CorsFilter() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*"); //for production add only origins which should be allowed to access now for demo purposes this accepts all.
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); //i would reduce this method list if not all methods used this is added just for demo purposes
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }
}

如果您使用的是春季启动应用程序,请确保包含新扫描程序在组件扫描中创建的

如果您使用'web.xml'进行配置:

然后添加过滤器

<filter>
    <filter-name>CORS</filter-name>
    <filter-class>com.mycompany.CorsFilter</filter-class>
</filter>

选项 A 在servlet上添加映射

<filter-mapping>
        <filter-name>CORS</filter-name>
        <servlet-name>MyServlet</servlet-name>
</filter-mapping>

选项 B 为所有应用添加过滤器:

<filter-mapping>
        <filter-name>CORS</filter-name>
        <url-pattern>/*</url-pattern> <!--this will add cors on all apps-->
</filter-mapping>

答案 1 :(得分:0)

用户详细信息由org.springframework.cloud.security.oauth2.resource.UserInfoTokenServices加载,因此值得在其中添加断点以查看它从您/我的端点获取的内容。

此类仅提取基本用户详细信息,实际上是查看设置ROLE_USER的硬编码角色的代码,因此建议您创建自己的详细信息以设置OAuth2Authentication正确的为用户。

答案 2 :(得分:0)

稍微改变了你的代码,它对我来说是本地的。

@EnableOAuth2Client
@RestController
@EnableAuthorizationServer
@SpringBootApplication
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class Application extends WebSecurityConfigurerAdapter {

@Autowired
OAuth2ClientContext oauth2ClientContext;


public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@GetMapping({"/user", "/me"})
public Map<String, String> user(Principal principal) {
    Authentication authentication = SecurityContextHolder.getContext()
            .getAuthentication();
    return Collections.singletonMap("name", principal == null ? "null" : principal.getName());
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("user").password("user").authorities(AuthorityUtils.NO_AUTHORITIES);
}

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.antMatcher("/me").authorizeRequests().anyRequest().authenticated();
        // @formatter:on
    }
}

@Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(filter);
    registration.setOrder(-100);
    return registration;
}

private Filter authFilter(ClientResources client, String path) {
    OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
            path);
    OAuth2RestTemplate template = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
    filter.setRestTemplate(template);
    UserInfoTokenServices tokenServices = new UserInfoTokenServices(
            client.getResource().getUserInfoUri(), client.getClient().getClientId());
    tokenServices.setRestTemplate(template);
    filter.setTokenServices(tokenServices);
    return filter;
    }
}

class ClientResources {

@NestedConfigurationProperty
private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();

@NestedConfigurationProperty
private ResourceServerProperties resource = new ResourceServerProperties();

public AuthorizationCodeResourceDetails getClient() {
    return client;
}

public ResourceServerProperties getResource() {
    return resource;
    }
}

您需要注册authenticationTokenFilter,无需注册ssoFilter。

答案 3 :(得分:-1)

由于您的auth服务器和客户端都是从同一主机(localhost)提供的,因此您的Web浏览器可能会混淆哪个http端点属于哪个http cookie。

尝试将其中一个指定为127.0.0.1,将另一个指定为localhost,以便您的浏览器将http Cookie与其正确的终结点相关联。