SpringCloud(六) oauth2认证中心(单点登陆)

本文详细介绍了如何使用SpringCloud OAuth2实现微服务统一认证授权,包括四种授权方式的特性,以及服务端和客户端的具体配置步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringCloud(六) oauth2认证中心(单点登陆)

1.介绍
在Spring Cloud需要使用OAUTH2来实现多个微服务的统一认证授权,通过向OAUTH服务发送某个类型的grant type进行集中认证和授权,从而获得access_token,而这个token是受其他微服务信任的,我们在后续的访问可以通过access_token来进行,从而实现了微服务的统一认证授权

OAuth 2.0定义了四种授权方式。

密码模式(resource owner password credentials)
授权码模式(authorization code)
简化模式(implicit)
客户端模式(client credentials)

密码模式(resource owner password credentials)这种模式是最不推荐的,因为client可能存了用户密码 这种模式主要用来做遗留项目升级为oauth2的适配方案 当然如果client是自家的应用,也是可以
支持refresh token

授权码模式(authorization code)这种模式算是正宗的oauth2的授权模式设计了auth code,通过这个code再获取token支持refresh token

简化模式(implicit)这种模式比授权码模式少了code环节,回调url直接携带token这种模式的使用场景是基于浏览器的应用这种模式基于安全性考虑,建议把token时效设置短一些不支持refresh token

客户端模式(client credentials)这种模式直接根据client的id和密钥即可获取token,无需用户参与这种模式比较合适消费api的后端服务,比如拉取一组用户信息等不支持refresh token,主要是没有必要 refresh token的初衷主要是为了用户体验不想用户重复输入账号密码来换取新token,因而设计了refresh token用于换取新token

这种模式由于没有用户参与,而且也不需要用户账号密码,仅仅根据自己的id和密钥就可以换取新token,因而没必要refresh token
代码模块展示
在这里插入图片描述
SSO 设计分为服务端和客户端2个部分,sso服务端为每个应用提供了统一的访问控制和授权认证服务,在模块merchant-sso中进行开发和包含用户登陆设计 主页设计 认证服务设计等
merchant-sso 服务端 配置
pom.xml的配置

server:
  port: 8000
  session:
        cookie:
        name: SESSIONID
 eureka:
   client:
     serviceUrl:
       defaultZone: http://localhost:8761/eureka/
  encrypt:
      failOnError: false
  spring:
     datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/myzipkin?characterEncoding=utf8&useSSL=false
        username: myzipkin
        password: myzipkin
       # 初始化大小,最小,最大
        initialSize: 5
        minIdle: 5
        maxActive: 20
     # 配置获取连接等待超时的时间
        maxWait: 60000
     # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        timeBetweenEvictionRunsMillis: 60000
     # 配置一个连接在池中最小生存的时间,单位是毫秒
        minEvictableIdleTimeMillis: 300000
         validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
   # 打开PSCache,并且指定每个连接上PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
   #配置监控统计拦截的filters,去掉后监控界面sql将无法统计,'wall'用于防火墙
      filters: stat,wall,log4j
   # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
   # 合并多个DruidDataSource的监控数据
   #useGlobalDataSourceStat=true
   jpa:
      database: MYSQL
      show-sql: false
      ## Hibernate ddl auto (validate|create|create-drop|update)
      hibernate:
        ddl-auto: none
        naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
      properties:
        hibernate:
          dialect: org.hibernate.dialect.MySQL5Dialect
      ---    ##FeignClient超时设置
   spring.cloud.loadbalancer.retry.enabled: true
   hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:10000 
   ribbon.ConnectTimeout: 250 ribbon.ReadTimeout: 1000  
   ribbon.OkToRetryOnAllOperations: true   
   ribbon.MaxAutoRetriesNextServer: 2 ribbon.MaxAutoRetries: 1

bootstrap.yml的配置
在这里插入图片描述

启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
@EnableHystrix
@EnableFeignClients(basePackages = “com.demo”)
@ComponentScan(basePackages = “com.demo”)
public class MerchantSsoApplication {
public static void main(String[] args) {
SpringApplication.run(MerchantSsoApplication.class, args);
}
}
认证中心 主要类
@Configuration
@EnableAuthorizationServer
public class OAuthConfigurer extends AuthorizationServerConfigurerAdapter {

@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    //非对称加密
    KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource(
            "keystore.jks"), "tc123456".toCharArray()).getKeyPair("tycoonclient");
    //对称加密
   // converter.setSigningKey("123");
    converter.setKeyPair(keyPair);
    return converter;
}

@Override
public void configure(ClientDetailsServiceConfigurer clients)
        throws Exception {
    clients.inMemory().withClient("ssoclient").secret("ssosecret")
            .autoApprove(true)
            .authorizedGrantTypes("authorization_code", "refresh_token").scopes("openid");
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security)
        throws Exception {
    security.tokenKeyAccess("permitAll()").checkTokenAccess(
            "isAuthenticated()").allowFormAuthenticationForClients();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
        throws Exception {
    endpoints.accessTokenConverter(jwtAccessTokenConverter());
}

}
其中,使用注解@EnableAuthorizationServer 启用了认证服务器功能 这里使用令牌 token的鉴权机制为sso客户端提供授权认证的方法
管理令牌JWT 创建一个数字证书 利用jdk创建证书 这个自行百度

创建类SecurityConfiguration
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
@Qualifier(“dataSource”)
private DataSource dataSource;

@Override
protected void configure(AuthenticationManagerBuilder auth)
        throws Exception {
    auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
    //remember me
    auth.eraseCredentials(false);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.formLogin().loginPage("/login").permitAll().successHandler(loginSuccessHandler())
            .and().authorizeRequests()
            .antMatchers("/images/**", "/checkcode", "/scripts/**", "/styles/**").permitAll()
            .anyRequest().authenticated()
            .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
            .and().exceptionHandling().accessDeniedPage("/deny")
            .and().rememberMe().tokenValiditySeconds(86400).tokenRepository(tokenRepository());//记住24小时
}

@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Bean
public JdbcTokenRepositoryImpl tokenRepository(){
    JdbcTokenRepositoryImpl jtr = new JdbcTokenRepositoryImpl();
    jtr.setDataSource(dataSource);
    return jtr;
}

@Bean
public LoginSuccessHandler loginSuccessHandler(){
    return new LoginSuccessHandler();
}

}

服务端搭建基本完成

接下来客户端搭建
在这里插入图片描述

配置pom.xml

<dependencies>
    <dependency>
        <groupId>com.demo</groupId>
        <artifactId>merchant-client</artifactId>
        <version>${project.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

在客户端启动安全管理功能和OAUTH2的sso客户端的功能
@Configuration
@EnableOAuth2Sso
@EnableConfigurationProperties(SecuritySettings.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private SecuritySettings settings;

@Autowired
private RoleFuture roleFuture;
@Autowired
private CacheComponent cacheComponent;

@Override
public void configure(HttpSecurity http) throws Exception {
    http
            .antMatcher("/**").authorizeRequests()
            .antMatchers(settings.getPermitall().split(",")).permitAll()
            .anyRequest().authenticated()
            .and().csrf().requireCsrfProtectionMatcher(csrfSecurityRequestMatcher())
            .csrfTokenRepository(csrfTokenRepository()).and()
            .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
            .logout().logoutUrl("/logout").permitAll()
            .logoutSuccessUrl(settings.getLogoutsuccssurl())
            .and()
            .exceptionHandling().accessDeniedPage(settings.getDeniedpage());
}

@Bean
public CustomFilterSecurityInterceptor customFilter() throws Exception{
    CustomFilterSecurityInterceptor customFilter = new CustomFilterSecurityInterceptor();
    customFilter.setSecurityMetadataSource(securityMetadataSource());
    customFilter.setAccessDecisionManager(accessDecisionManager());
    customFilter.setAuthenticationManager(authenticationManager);
    return customFilter;
}

@Bean
public CustomAccessDecisionManager accessDecisionManager() {
    return new CustomAccessDecisionManager();
}

@Bean
public CustomSecurityMetadataSource securityMetadataSource() {
    return new CustomSecurityMetadataSource(roleFuture, cacheComponent);
}


//开放接口禁止防跨站伪造攻击
private CsrfSecurityRequestMatcher csrfSecurityRequestMatcher(){
    CsrfSecurityRequestMatcher csrfSecurityRequestMatcher = new CsrfSecurityRequestMatcher();
    List<String> list = new ArrayList<String>();
    list.add("/openhttp/");//完全开放
    csrfSecurityRequestMatcher.setExecludeUrls(list);
    return csrfSecurityRequestMatcher;
}

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 = new Cookie("XSRF-TOKEN",
                        csrf.getToken());
                cookie.setPath("/");
                response.addCookie(cookie);
            }
            filterChain.doFilter(request, response);
        }
    };
}

private CsrfTokenRepository csrfTokenRepository() {
    HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setHeaderName("X-XSRF-TOKEN");
    return repository;
}

}
@EnableOAuth2Sso这个注解启动了应用的sso客户端的功能
其他都是OaAuth2里面实现类

现在基本上搭建成功了
其他服务需要接入sso只需要在配置文件加如下配置
在这里插入图片描述

# MCloud - OAuth2 认证中心 [![Build Status](https://www.travis-ci.org/heyuxian/mcloud-oauth2-server.svg?branch=master)](https://www.travis-ci.org/heyuxian/mcloud-oauth2-server) [![Coverage Status](https://coveralls.io/repos/github/heyuxian/mcloud-oauth2-server/badge.svg?branch=master)](https://coveralls.io/github/heyuxian/mcloud-oauth2-server?branch=master) [![License](https://img.shields.io/badge/License-Apache 2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ## 简介 `mcloud-oauth-server` 基于**Spring OAuth2**,实现了**OAuth2**认证服务器以及资源服务器,并以 **Restful API** 的方式提供了**OAuth** 客户端以及用户的管理功能。 项目中主要使用了以下技术: - **Java8** - **Spring 相关** Spring, Spring Mvc, Spring Cloud, Spring data jpa, Spring Boot,Hibernate - **mapstruct** 主要用于DTO 与 Entity 之间的转换 - **flywaydb** 以版本化的方式管理数据库脚本 - **thymeleaf** 模板框架,用于实现后台管理界面 - **Redis** 主要用作缓存实现 (暂未实现) - **lombok** ## 认证流程 **OAuth2**认证流程可参考博客 [理解OAuth 2.0](http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html) ,此处不再赘述。 ## Features - **认证服务器** 使用Spring Security 结合 JWT Token 实现认证服务,提供了功能完整的 OAuth2 认证服务器。 - **资源服务器** 实现了以下两种方式进行OAuth2 相关资源的管理 - 以 RestAPI 形式提供服务来管理资源:`http://localhost:8043/uaa/swagger-ui.html` - 以 Thymeleaf + [AdminBSBMaterialDesign](https://github.com/gurayyarar/AdminBSBMaterialDesign) 实现的管理端: ​ **用户端** ![image](https://user-images.githubusercontent.com/30259465/33719089-a021befc-db9a-11e7-9a59-179f531dcfe4.png) **管理员** ![image](https://user-images.githubusercontent.com/30259465/33719145-c7c0af54-db9a-11e7-8c52-f92df2cdd7a1.png) ## 快速使用 **创建数据库** 请使用 mysql 客户端或是其他你喜欢的工具创建数据库,默认的数据库名称为 `db_oauth` **使用flywaydb初始化数据库** 修改 `pom.xml`中 **flywaydb** 插件的数据库名,用户名以及密码: **pom.xml** ```xml <plugin> <groupId>org.flywaydb</groupId> <artifactId>flyway-maven-plugin</artifactId> <version>4.2.0</version> <configuration> <user>root</user> <password>你的数据库密码</password> <driver>com.mysql.jdbc.Driver</driver> <url>jdbc:mysql://localhost:3306/数据库名称</url> </configuration> </plugin> ``` 修改相关配置之后,请在项目根目录下执行maven命令: ``` mvn flyway:clean flyway:migrate ``` 修改项目的数据库配置: **application.yml** ```yaml spring: datasource: url: jdbc:mysql://localhost/数据库名称 username: 用户 password: 密码 driver-class-name: com.mysql.jdbc.Driver ``` **启动OAuth2认证服务** 所有准备工作已经完成,现在,让我们启动服务,在项目根目录下运行maven命令: ``` mvn clean install mvn spring-boot:run ``` 如果你使用的是 Idea 或 eclipse 开发,请直接运行 **OAuthServerApplication** 这个方法即可启动服务。 **访问地址** ``` http://localhost:8043/uaa/swagger-ui.html ``` ![uaa](https://user-images.githubusercontent.com/30259465/31441550-16f2053e-aec6-11e7-9568-93cd35dbc1dd.png) ## 使用 Postman 调试API **前提:** 了解Postman并且安装了 **Chrome** 的 **Postman** 插件 首先自然是启动服务,然后我们在Postman中请求 `http://localhost:8043/uaa/api/v1/users/` ,此时因为还未进行认证,所以服务器返回的是 `401` 的状态码: ![OAuth fail](https://user-images.githubusercontent.com/30259465/31854106-e2270cf6-b6c6-11e7-91e3-f66ec6fef9fd.png) 现在我们通过Postman 自带的OAuth认证功能进行认证: ![qq 20171022011928](https://user-images.githubusercontent.com/30259465/31854237-11da1e38-b6c8-11e7-90b0-40dc54325b67.png) ![qq 20171022012054](https://user-images.githubusercontent.com/30259465/31854178-c1ad282e-b6c7-11e7-95a8-e2b5b006fcab.png) 相关项: - **Token Name** access_token - **Auth URL**: http://localhost:8043/uaa/oauth/authorize - **Access Token URL**: http://localhost:8043/uaa/oauth/token - **Client ID**: mcloud-blog - **Client Secret**: 123456 - **Scope**: 可以为空,此处不填 - **Grant Type**: Authorization code ![qq 20171126221612](https://user-images.githubusercontent.com/30259465/33240822-6c0d75ee-d2f7-11e7-810c-5dd523714c86.jpg) 默认用户: - **用户名** user - **密码** 123456 ![qq 20171022012701](https://user-images.githubusercontent.com/30259465/31854253-51b0a55e-b6c8-11e7-8415-d0ff4a242a85.png) 当我们授权之后,就可以得到 **access_token**,此时选中并点击 Use Token,然后我们再次访问之前无权限的 API ![qq 20171022013209](https://user-images.githubusercontent.com/30259465/31854294-d78b8fae-b6c8-11e7-8c77-46878e9159ef.png) 服务器已成功返回 `200` 的状态码,并返回了用户列表。 ## 其他 1. 因本项目使用了 **lombok** 进行开发,在开发之前需要安装插件,若使用的是 **IDEA** 进行开发,请自行搜索并安装 **lombok** 插件,否则会导致编译错误 2. 若是进行二次开发,请替换 `keystore.jks` **(非常重要)** ,否则会导致安全风险,`keystore.jks` 可使用jdk 工具生成,也可自行使用其他工具生成非对称密钥对。 ## 问题及建议 如果你有任何好的意见以及建议,请提 [Issue](https://github.com/heyuxian/mcloud-oauth2-server/issues/new)。 如果你觉得此项目对你有所帮助,欢迎点赞支持。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值