基于oauth2简单实现SSO

  • 在实现SSO之前,先要说一下**@EnableResourceServer@EnableOAuth2Sso**
  1. 一般网关处我们使用EnableResourceServer时,可以支持任意的oauth2授权模型,网关声明称资源服务器可以配置ResourceServerConfigurerAdapter,我们可以配置放行的路径等等内容。
  2. 如果网关处使用EnableOAuth2Sso,在所有请求转发之前就首先要到认证服务器上去校验信息,使用授权码模式,clientid与clientsecret来确认进行oauth2的登陆,跳转登陆页面在进行登陆。

下面我们来简单搭建一个SSO的小项目
  • 搭建认证服务器

    我们将客户端信息存储在mysql中,token使用jwt。

    依赖包只需要oauth2,我cloud用的版本是Greenwich.SR2

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>
    
    1. 配置AuthorizationServerConfigurerAdapter

      package cn.hs.sys.config;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.security.authentication.AuthenticationManager;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
      import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
      import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
      import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
      import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
      import org.springframework.security.oauth2.provider.token.TokenStore;
      import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
      import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
      
      import javax.sql.DataSource;
      
      /**
       * @description:
       * @Author: huangsan
       * @Date: 2020/5/8 4:46 下午
       */
      @Configuration
      @EnableAuthorizationServer
      public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {
      
          @Autowired
          private AuthenticationManager authenticationManager;
          @Autowired
          private DataSource dataSource;
          @Autowired
          private BCryptPasswordEncoder passwordEncoder;
      
          @Override
          public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
              endpoints
                      .tokenStore(tokenStore())
                      .tokenEnhancer(jwtAccessTokenConverter())
                      .authenticationManager(authenticationManager);
          }
      
          @Bean
          public TokenStore tokenStore() {
              return new JwtTokenStore(jwtAccessTokenConverter());
          }
      
          @Bean
          public JwtAccessTokenConverter jwtAccessTokenConverter() {
              JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
              converter.setSigningKey("123456");
              return converter;
          }
      
          @Override
          public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
              System.out.println("------"+passwordEncoder.encode("123456"));
              clients.jdbc(dataSource);
          }
      
          @Override
          public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
              security
                      .tokenKeyAccess("isAuthenticated()")
                      .checkTokenAccess("isAuthenticated()");
          }
      }
      
    2. 配置WebSecurityConfigurerAdapter

      package cn.hs.sys.config;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.security.authentication.AuthenticationManager;
      import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
      import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
      import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.crypto.password.PasswordEncoder;
      
      /**
       * @description:
       * @Author: huangsan
       * @Date: 2020/5/8 4:47 下午
       */
      @Configuration
      @EnableWebSecurity
      public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
      
          @Autowired
          private UserDetailsService userDetailsService;
      
          @Autowired
          private PasswordEncoder passwordEncoder;
      
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth.userDetailsService(userDetailsService)
                      .passwordEncoder(passwordEncoder);
          }
        
          @Bean
          @Override
          public AuthenticationManager authenticationManagerBean() throws Exception {
              return super.authenticationManagerBean();
          }
      }
      
    3. 配置UserDetailsService(这里自己实现逻辑返回UserDetails即可)

      package cn.hs.sys.config;
      
      import cn.hs.sys.Constant;
      import cn.hs.sys.dao.SysUserEntity;
      import cn.hs.sys.dao.UserPermissionRepository;
      import org.apache.commons.lang.StringUtils;
      import org.springframework.security.core.GrantedAuthority;
      import org.springframework.security.core.authority.SimpleGrantedAuthority;
      import org.springframework.security.core.userdetails.User;
      import org.springframework.security.core.userdetails.UserDetails;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.core.userdetails.UsernameNotFoundException;
      import org.springframework.stereotype.Service;
      
      import javax.annotation.Resource;
      import java.util.ArrayList;
      import java.util.List;
      
      /**
       * @description:
       * @Author: huangsan
       * @Date: 2020/5/8 4:53 下午
       */
      @Service
      public class UserDetailsServiceImpl implements UserDetailsService {
      
          @Resource
          private UserPermissionRepository userPermissionRepository;
      
          @Override
          public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
              if (StringUtils.isBlank(username)) {
                  throw new UsernameNotFoundException("账号错误");
              }
              SysUserEntity sysUserEntity = userPermissionRepository.findUserIdByName(username);
              if (sysUserEntity == null) {
                  throw new UsernameNotFoundException("账号异常");
              }
              if (Constant.USER_OFF.equals(sysUserEntity.getUserStatus())) {
                  throw new UsernameNotFoundException("账号状态异常");
              }
              if (sysUserEntity.getUserId() != null) {
                  List<String> permissionStrs = userPermissionRepository.listPermissionById(sysUserEntity.getUserId());
      
                  List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
                  permissionStrs.forEach(permissionStr -> {
                      if (StringUtils.isNotBlank(permissionStr)) {
                          GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permissionStr);
                          grantedAuthorities.add(grantedAuthority);
                      }
                  });
                  //密码加密方式为:passwordEncoder.encode()
                  return new User(username, sysUserEntity.getUserPassword(), grantedAuthorities);
              } else {
                  throw new UsernameNotFoundException("账号异常");
              }
          }
      }
      
    4. 配置文件如下(没什么东西,主要就是mysql的内容,eureka自行去掉吧)

      server:
        port: 52188
      spring:
        application:
          name: hs-auth
        datasource:
          url: jdbc:mysql://localhost:3306/hs_cloud?characterEncoding=utf8&characterSetResults=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
      eureka:
        client:
          service-url:
            defaultZone: http://127.0.0.1:52199/eureka
      

认证服务器的内容基本都是一样,没什么特别的地方我就直接贴代码了,对于客户端来说有一些需要注意的地方。

  • 配置客户端

    注意客户端不能使用EnableResourceServer注解

    1. 引入相关依赖

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-oauth2</artifactId>
      </dependency>
      
    2. 在启动类上增加@EnableOAuth2Sso注解

    3. 创建测试web测试类,返回数据

    4. 配置yml文件

      server:
        port: 52109
        servlet:
          context-path: /sys #特别需要配置,如果是/会反复跳转登陆页面
      security:
        oauth2:
          resource:
            jwt:
              key-uri: http://localhost:52188/oauth/token_key
          client:
            client-id: hs-system #客户端id
            client-secret: 123456 #客户端口令
            access-token-uri: http://localhost:52188/oauth/token #获取令牌路径
            user-authorization-uri: http://localhost:52188/oauth/authorize #获取授权路径
      
  • 相同的方式配置另一个客户端

    和第一个客户端一样,注意更改path

  • 配置完客户端需要配置登陆跳转路径和自动授权(下面是sql插入语句自行修改)

    INSERT INTO `hs_cloud`.`oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('hs-gateway', NULL, '$2a$10$p/siIwq2lUsOpg6gZC1V5epmeLMdO6BrfKnO36.5ZCn9eHOcibiUi', 'read', 'authorization_code,refresh_token,password', 'http://localhost:52100/zuul/login', NULL, 3600, 360000, NULL, 'read'); INSERT INTO `hs_cloud`.`oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('hs-modules-back', NULL, '$2a$10$p/siIwq2lUsOpg6gZC1V5epmeLMdO6BrfKnO36.5ZCn9eHOcibiUi', 'read', 'authorization_code,refresh_token,password', 'http://localhost:52110/back/login', NULL, 3600, 360000, NULL, 'read');

    主要注意web_server_redirect_uri与autoapprove,配置autoapprove可以跳过授权的步骤,直接授权

  • 成果演示(文字描述是:俩个客户端访问的时候都会去授权服务器,如果没有登陆会跳转登陆页,当一个客户端登录后,可直接访问,不需登陆。视频传上来好麻烦,就不传了,手动狗头。)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值