工作笔记

SpringCloud 搭建OAuth2 统一授权服务

2018-12-20
阅读次数:

“Spring Cloud Security OAuth2 是 Spring 对 OAuth2 的开源实现,与Spring Cloud技术栈无缝集成,使用默认配置,开发者只需要添加注解就能完成 OAuth2 授权服务的搭建。”

Demo工程准备

1. 添加Oauth依赖

SpringBoot工程中添加相关pom依赖,pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.oauth</groupId>
    <artifactId>oauth-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring-boot.version>2.1.0.RELEASE</spring-boot.version>

        <spring-cloud.version>Greenwich.M2</spring-cloud.version>
    </properties>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>http://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2. 添加访问测试接口

添加测试访问接口如下:

@RestController
public class DemoController {

    @GetMapping(path = "/hello")
    public String hello() {
        return "hello demo";
    }
}

运行工程后使用浏览器访问地址:http://localhost:8080/,发现接口已经加入了安全控制,默认需要输入用户名密码进行验证。

要更改默认的安全配置,通过WebSecurityConfigurerAdapter进行扩展即可,我们首先配置内存中保存的用户名密码进行验证。

@Configuration
@EnableWebSecurity( debug = true )
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.rememberMe()
            .and()
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .antMatchers("/login**").permitAll()
                    .antMatchers("/logout**").permitAll()
                    .antMatchers("/**").hasAnyRole("ADMIN", "USER")
                    .antMatchers("/auth/**", "/oauth2/**").permitAll()
            .and()
                .formLogin().permitAll()
            .and()
                .logout()
                    .logoutSuccessUrl("/logout_success")
                    .invalidateHttpSession(true)
                    .permitAll()
            .and()
                .csrf()
                    .disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication() // creating user in memory
                .withUser("user")
                .password("password").roles("USER")
                .and().withUser("admin")
                .password("password").authorities("ROLE_ADMIN");
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        // provides the default AuthenticationManager as a Bean
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

}

以上配置开启了basic认证和默认的登录表单界面,为使流程更加直观,接口中简单添加个登出成功接口:

@RestController
public class DemoController {;
    @GetMapping(path = "/hello")
    public String hello() {
        return "hello";
    }

    @GetMapping(value="/logout_success")
    public String logout() {
        return "logged out";
    }
}

基本的表单登录功能演示:

添加OAuth2 验证

1.授权服务器配置

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetails());
    }


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
                .userDetailsService(userDetailsService())
                .authenticationManager(authenticationManager);
        endpoints.tokenServices(defaultTokenServices());
        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.DELETE);
    }


    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()");
        security.checkTokenAccess("isAuthenticated()");
        security.allowFormAuthenticationForClients();
    }


    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(
                User.withUsername("user").password("password").roles("USER").build());
        return manager;
    }


    @Bean
    public ClientDetailsService clientDetails() {

        InMemoryClientDetailsService inMemoryClientDetailsService = new InMemoryClientDetailsService();

        Map<String, ClientDetails> clientDetailsStore = new HashMap<>();
        clientDetailsStore.put("test_client", new BaseClientDetails("test_client", "",
                "all", "password, refresh_token", "ROLE_CLIENT, ROLE_TRUSTED_CLIENT"));

        inMemoryClientDetailsService.setClientDetailsStore(clientDetailsStore);


        return inMemoryClientDetailsService;
    }

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

    @Bean
    public DefaultTokenServices defaultTokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(clientDetails());
        tokenServices.setAccessTokenValiditySeconds(60 * 30); // token有效期自定义设置,默认12小时
        tokenServices.setRefreshTokenValiditySeconds(60 * 60);//默认30天,这里修改
        return tokenServices;
    }

}

2.资源服务器配置

资源服务器用来配置哪些资源是需要通过token进行验证的。

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

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

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/hello**")
                .and()
                .authorizeRequests()
                .antMatchers("/hello").authenticated();

    }
}

3.结果测试

通过Oauth2获取token后访问接口,结果:

小结

本例中演示了Spring Cloud Security的默认设置(表单登录)及token授权验证,源代码地址: https://github.com/lizhiyong2000/tutorials/tree/master/oauth-demo 后续将继续基于Spring Cloud Security构建SSO功能。

参考链接


评论

目录