• Spring-Security-Oauth2 基于JDBC存储令牌和RBAC权限认证


    相关配置来自李哥博客:  https://funtl.com/zh/spring-security-oauth2/   (本文仅记录自己学习过程,说的不详细,可以观看李哥博客)

    认证服务器和资源服务器pom.xml配置  (李哥博客用的是tk.mybatis 我用的是spring  jpa)

    <dependencies>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
     
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    认证服务器: 

    初始化JDBC相关表:

    CREATE TABLE `clientdetails` (
      `appId` varchar(128) NOT NULL,
      `resourceIds` varchar(256) DEFAULT NULL,
      `appSecret` varchar(256) DEFAULT NULL,
      `scope` varchar(256) DEFAULT NULL,
      `grantTypes` varchar(256) DEFAULT NULL,
      `redirectUrl` varchar(256) DEFAULT NULL,
      `authorities` varchar(256) DEFAULT NULL,
      `access_token_validity` int(11) DEFAULT NULL,
      `refresh_token_validity` int(11) DEFAULT NULL,
      `additionalInformation` varchar(4096) DEFAULT NULL,
      `autoApproveScopes` varchar(256) DEFAULT NULL,
      PRIMARY KEY (`appId`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE `oauth_access_token` (
      `token_id` varchar(256) DEFAULT NULL,
      `token` blob,
      `authentication_id` varchar(128) NOT NULL,
      `user_name` varchar(256) DEFAULT NULL,
      `client_id` varchar(256) DEFAULT NULL,
      `authentication` blob,
      `refresh_token` varchar(256) DEFAULT NULL,
      PRIMARY KEY (`authentication_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE `oauth_approvals` (
      `userId` varchar(256) DEFAULT NULL,
      `clientId` varchar(256) DEFAULT NULL,
      `scope` varchar(256) DEFAULT NULL,
      `status` varchar(10) DEFAULT NULL,
      `expiresAt` timestamp NULL DEFAULT NULL,
      `lastModifiedAt` timestamp NULL DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE `oauth_client_details` (
      `client_id` varchar(128) NOT NULL,
      `resource_ids` varchar(256) DEFAULT NULL,
      `client_secret` varchar(256) DEFAULT NULL,
      `scope` varchar(256) DEFAULT NULL,
      `authorized_grant_types` varchar(256) DEFAULT NULL,
      `web_server_redirect_uri` varchar(256) DEFAULT NULL,
      `authorities` varchar(256) DEFAULT NULL,
      `access_token_validity` int(11) DEFAULT NULL,
      `refresh_token_validity` int(11) DEFAULT NULL,
      `additional_information` varchar(4096) DEFAULT NULL,
      `autoapprove` varchar(256) DEFAULT NULL,
      PRIMARY KEY (`client_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE `oauth_client_token` (
      `token_id` varchar(256) DEFAULT NULL,
      `token` blob,
      `authentication_id` varchar(128) NOT NULL,
      `user_name` varchar(256) DEFAULT NULL,
      `client_id` varchar(256) DEFAULT NULL,
      PRIMARY KEY (`authentication_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE `oauth_code` (
      `code` varchar(256) DEFAULT NULL,
      `authentication` blob
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE `oauth_refresh_token` (
      `token_id` varchar(256) DEFAULT NULL,
      `token` blob,
      `authentication` blob
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

     appllication.yml:

    server:
      port: 9999
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: (自己的数据库)
        username: (账号)
        password: (密码)
        hikari:
          minimum-idle: 5
          idle-timeout: 600000
          maximum-pool-size: 10
          auto-commit: true
          pool-name: MyHikariCP
          max-lifetime: 1800000
          connection-timeout: 30000
          connection-test-query: SELECT 1

     认证客服端:

    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
        @Bean
        @Primary
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource dataSource() {
            // 配置数据源(使用的是 HikariCP 连接池),以上注解是指定数据源,否则会有冲突
            return DataSourceBuilder.create().build();
        }
        @Bean
        public TokenStore tokenStore() {
            // 基于 JDBC 实现,令牌保存到数据
            return new JdbcTokenStore(dataSource());
        }
    
        @Bean
        public ClientDetailsService jdbcClientDetails() {
            // 基于 JDBC 实现,需要事先在数据库配置客户端信息
            return new JdbcClientDetailsService(dataSource());
        }
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            // 设置令牌
            endpoints.tokenStore(tokenStore());
        }
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            // 读取客户端配置
            clients.withClientDetails(jdbcClientDetails());
        }
    }

    用户授权:

    @Configuration
    public class UserDetailsServiceConfiguration implements UserDetailsService {
        @Autowired
        private TbUserService  tbUserService;
        @Autowired
        private TbPermissionService tbPermissionService;
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            TbUser tbUser  = tbUserService.findByUsername(username);
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
            if (tbUser != null) {
                // 获取用户授权
                List<TbPermission> tbPermissions = tbPermissionService.selectByUserId(tbUser.getId());
                // 声明用户授权
                tbPermissions.forEach(tbPermission -> {
                    if (tbPermission != null && tbPermission.getEnname() != null) {
                        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(tbPermission.getEnname());
                        grantedAuthorities.add(grantedAuthority);
                    }
                });
            }
    
            return new User(tbUser.getUsername(), tbUser.getPassword(), grantedAuthorities);
    
        }
    }

    安全配置:

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserDetailsServiceConfiguration userDetailsServiceConfiguration;
        @Bean
        public BCryptPasswordEncoder passwordEncoder() {
            // 设置默认的加密方式
            return new BCryptPasswordEncoder();
        }
        @Bean
        @Override
        public UserDetailsService userDetailsService(){
            return userDetailsServiceConfiguration;
        }
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // 使用自定义认证与授权
            auth.userDetailsService(userDetailsService());
        }
        @Override
        public void configure(WebSecurity web)  {
            // 将 check_token 暴露出去,否则资源服务器访问时报 403 错误
            web.ignoring().antMatchers("/oauth/check_token");
        }
    }
    

     获取用户信息和权限信息目录和代码:

    @Repository
    public  interface TbPermissionRepository extends JpaRepository<TbPermission,Long> {
        @Query(value = "SELECT
    " +
                "  p.*
    " +
                "FROM
    " +
                "  tb_user AS u
    " +
                "  LEFT JOIN tb_user_role AS ur
    " +
                "    ON u.id = ur.user_id
    " +
                "  LEFT JOIN tb_role AS r
    " +
                "    ON r.id = ur.role_id
    " +
                "  LEFT JOIN tb_role_permission AS rp
    " +
                "    ON r.id = rp.role_id
    " +
                "  LEFT JOIN tb_permission AS p
    " +
                "    ON p.id = rp.permission_id
    " +
                "WHERE u.id = ?1",nativeQuery = true)
        public List<TbPermission> selectByUserId(Long id);
    }
    @Repository
    public interface TbUserRepository extends JpaRepository<TbUser,Long> {
        @Query(value = "select * from tb_user where username = ?1",nativeQuery = true)
        public TbUser findByUsername(String username);
    }
    
    @Service
    public class TbPermissionService{
        @Autowired
        private TbPermissionRepository tbPermissionRepository;
        public List<TbPermission> selectByUserId(Long id){
            List<TbPermission> tbPermissions = tbPermissionRepository.selectByUserId(id);
            return tbPermissions;
        }
    }
    
    @Service
    public class TbUserService {
        @Autowired
        private TbUserRepository tbUserRepository;
        public TbUser findByUsername(String username){
            TbUser byUsername = tbUserRepository.findByUsername(username);
            return byUsername;
        }
    }

    客服端表:oauth_client_details

    获取code请求地址(GET请求):  http://{you ip}:{you port}/oauth/authorize?client_id=client&response_type=code (client_id为上图中的client_id,成功之后会回调url 为上面的web_server_redicrct_uri)

    获取token请求地址(POST请求:) :http://client:secret@{you ip}:{you port}/oauth/token   携带参数为: grant_type (为上图中的authorization_grant_type)  code (上面返回的code)

    资源服务器:  资源服务器就是普通的CRUD和对接Oauth2认证授权服务端

    RBAC相关表:

    CREATE TABLE `tb_permission` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `parent_id` bigint(20) DEFAULT NULL COMMENT '父权限',
      `name` varchar(64) NOT NULL COMMENT '权限名称',
      `enname` varchar(64) NOT NULL COMMENT '权限英文名称',
      `url` varchar(255) NOT NULL COMMENT '授权路径',
      `description` varchar(200) DEFAULT NULL COMMENT '备注',
      `created` datetime NOT NULL,
      `updated` datetime NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8 COMMENT='权限表';
    insert  into `tb_permission`(`id`,`parent_id`,`name`,`enname`,`url`,`description`,`created`,`updated`) values 
    (37,0,'系统管理','System','/',NULL,'2019-04-04 23:22:54','2019-04-04 23:22:56'),
    (38,37,'用户管理','SystemUser','/users/',NULL,'2019-04-04 23:25:31','2019-04-04 23:25:33'),
    (39,38,'查看用户','SystemUserView','',NULL,'2019-04-04 15:30:30','2019-04-04 15:30:43'),
    (40,38,'新增用户','SystemUserInsert','',NULL,'2019-04-04 15:30:31','2019-04-04 15:30:44'),
    (41,38,'编辑用户','SystemUserUpdate','',NULL,'2019-04-04 15:30:32','2019-04-04 15:30:45'),
    (42,38,'删除用户','SystemUserDelete','',NULL,'2019-04-04 15:30:48','2019-04-04 15:30:45');
    
    CREATE TABLE `tb_role` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `parent_id` bigint(20) DEFAULT NULL COMMENT '父角色',
      `name` varchar(64) NOT NULL COMMENT '角色名称',
      `enname` varchar(64) NOT NULL COMMENT '角色英文名称',
      `description` varchar(200) DEFAULT NULL COMMENT '备注',
      `created` datetime NOT NULL,
      `updated` datetime NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8 COMMENT='角色表';
    insert  into `tb_role`(`id`,`parent_id`,`name`,`enname`,`description`,`created`,`updated`) values 
    (37,0,'超级管理员','admin',NULL,'2019-04-04 23:22:03','2019-04-04 23:22:05');
    
    CREATE TABLE `tb_role_permission` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `role_id` bigint(20) NOT NULL COMMENT '角色 ID',
      `permission_id` bigint(20) NOT NULL COMMENT '权限 ID',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8 COMMENT='角色权限表';
    insert  into `tb_role_permission`(`id`,`role_id`,`permission_id`) values 
    (37,37,37),
    (38,37,38),
    (39,37,39),
    (40,37,40),
    (41,37,41),
    (42,37,42);
    
    CREATE TABLE `tb_user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `username` varchar(50) NOT NULL COMMENT '用户名',
      `password` varchar(64) NOT NULL COMMENT '密码,加密存储',
      `phone` varchar(20) DEFAULT NULL COMMENT '注册手机号',
      `email` varchar(50) DEFAULT NULL COMMENT '注册邮箱',
      `created` datetime NOT NULL,
      `updated` datetime NOT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `username` (`username`) USING BTREE,
      UNIQUE KEY `phone` (`phone`) USING BTREE,
      UNIQUE KEY `email` (`email`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8 COMMENT='用户表';
    insert  into `tb_user`(`id`,`username`,`password`,`phone`,`email`,`created`,`updated`) values 
    (37,'admin','$2a$10$9ZhDOBp.sRKat4l14ygu/.LscxrMUcDAfeVOEPiYwbcRkoB09gCmi','15888888888','lee.lusifer@gmail.com','2019-04-04 23:21:27','2019-04-04 23:21:29');
    
    CREATE TABLE `tb_user_role` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `user_id` bigint(20) NOT NULL COMMENT '用户 ID',
      `role_id` bigint(20) NOT NULL COMMENT '角色 ID',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8 COMMENT='用户角色表';
    insert  into `tb_user_role`(`id`,`user_id`,`role_id`) values 
    (37,37,37);

    application.yml:

    server:
      port: 10000
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: (自己的数据库)
        username: (账号)
        password: (密码)
        hikari:
          minimum-idle: 5
          idle-timeout: 600000
          maximum-pool-size: 10
          auto-commit: true
          pool-name: MyHikariCP
          max-lifetime: 1800000
          connection-timeout: 30000
          connection-test-query: SELECT 1
    security:
      oauth2:
        client:
          client-id: client
          client-secret: secret
          access-token-uri: http://localhost:9999/oauth/token
          user-authorization-uri: http://localhost:9999/oauth/authorize
        resource:
          token-info-uri: http://localhost:9999/oauth/check_token
    @Configuration
    @EnableResourceServer
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
    public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .exceptionHandling()
                    .and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .authorizeRequests()
                    // 以下为配置所需保护的资源路径及权限,需要与认证服务器配置的授权部分对应
                    .antMatchers("/").hasAuthority("System")
                    .antMatchers("/view/**").hasAuthority("SystemContentView")
                    .antMatchers("/insert/**").hasAuthority("SystemContentInsert")
                    .antMatchers("/update/**").hasAuthority("SystemContentUpdate")
                    .antMatchers("/delete/**").hasAuthority("SystemContentDelete");
        }
    }
  • 相关阅读:
    BUUCTF | SQL COURSE 1
    BUUCTF | 高明的黑客
    element el-upload自定义上传显示进度条,多文件上传进度
    100行代码实现vue表单校验功能(小白自编)
    element-ui中validateField怎么验证部分表单字段的正确与否
    react解析html的dangerouslySetInnerHTML
    【Hyper-V】与【VirtualBox】【VMware】冲突的解决方法
    迁移到webpack4:从webpack.optimize.CommonsChunkPlugin到config.optimization.splitChunk,以及有个搜出来的中文解决办法是错的
    React 如何解析从后台读取的内容是html格式代码(带样式)
    Vue的elementUI实现自定义主题
  • 原文地址:https://www.cnblogs.com/zsifan/p/11745712.html
Copyright © 2020-2023  润新知