首页 > 解决方案 > 在服务器端设置基本身份验证

问题描述

我在一个应用程序中配置了资源和授权服务器。我使用带有资源所有者密码凭据的 spring-security oauth2。我可以在服务器端设置基本身份验证吗?我不想在前端做。我不知道我需要显示代码的哪一部分...当我想接收令牌时,我需要在邮递员中输入: 来自邮递员 我可以在服务器端配置它吗?

授权服务器:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter jwtTokenEnhancer;

    @Autowired
    private UserApprovalHandler userApprovalHandler;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore).tokenEnhancer(jwtTokenEnhancer).userApprovalHandler(userApprovalHandler)
                .authenticationManager(authenticationManager)
                .pathMapping("/oauth/token", "/login");
    }
}

资源服务器:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = "resource_id";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID).stateless(false);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .cors().and().csrf().disable()

                .authorizeRequests()
                .antMatchers("/swagger-ui.html#").permitAll()
                .antMatchers("/").authenticated()
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }
}

安全配置:

@Configuration
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(10);
    }


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    @Override
    public void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }


    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(jwtTokenEnhancer());
    }

    @Bean
    protected JwtAccessTokenConverter jwtTokenEnhancer() {
        converter.setSigningKey("Demo-Key-1");
        return converter;
    }

    @Bean
    @Autowired
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Bean
    @Autowired
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore);
        return store;
    }

    @Override
    @Order(Ordered.HIGHEST_PRECEDENCE)
    protected void configure(final HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/resources/**").permitAll()
                .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()
                .and().cors().and().csrf().disable();
    }
}

标签: javarestspring-securityspring-security-oauth2

解决方案


此答案附有完整且有效的示例

也许你在这里咬得比你能咀嚼的还多

例如:

.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()

/oauth/token端点必须保持受保护。这是授权服务器上向经过身份验证的客户端颁发令牌的端点。如果您打开它,系统可能会失败NullpointerException或出现其他异常,但是,上面的配置选项表明您可能对 OAuth2 的工作方式有些困惑。

我建议首先完全了解授权服务器与资源服务器。您绝对可以将两者结合起来,但它们会有非常不同的端点。

授权服务器 - 典型端点

/oauth/token - issues tokens
/oauth/authorize - issues authorization codes
/introspect - validates a token and returns token claims in a known format

资源服务器 - 例如,这些将是您的应用程序端点,需要Bearer令牌

/account/123/debit

并且这些端点期望具有授权标头的无状态请求

Authorization: Bearer <token value here>

资源服务器的控制器如下所示:

@PreAuthorize("hasRole('your-scope-role')")
@RequestMapping(value = "/hello")
@ResponseBody
public String hello(Principal principal) {
    return "Hello to " + principal.getName();
}

随意查看我为您创建的简单项目。

除此之外,我还推荐这个关于OAuth2 和 OpenID Connect的视频

在我的示例中,我已经像这样配置了客户端

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        InMemoryClientDetailsService clientDetails = new InMemoryClientDetailsService();
        BaseClientDetails client = new BaseClientDetails(
            "testclient",
            null,
            "testscope,USER,ADMIN",
            "password",
            null
        );
        client.setClientSecret(passwordEncoder.encode("secret"));
        clientDetails.setClientDetailsStore(
            Collections.singletonMap(
                client.getClientId(),
                client
            )
        );
        clients.withClientDetails(clientDetails);
    }

看一下这个简单的测试用例,客户端使用的是 http-basic 认证:

mvc.perform(
    post("/oauth/token")
            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
            .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
            .param("username", "admin")
            .param("password", "password")
            .param("grant_type", "password")
            .param("response_type", "token")
            .param("client_id", "testclient")
            .header("Authorization", "Basic " + Base64.encodeBase64String("testclient:secret".getBytes()))

这是客户端身份验证,使用 http-basic 方法:

.header("Authorization", "Basic " + Base64.encodeBase64String("testclient:secret".getBytes()))

推荐阅读