美文网首页权限认证框架
SpringSecurity结合OAuth2实现第三方授权

SpringSecurity结合OAuth2实现第三方授权

作者: 攻城老狮 | 来源:发表于2021-02-26 09:41 被阅读0次

    SpringSecurity结合OAuth2实现第三方授权


    一 OAuth2第三方登录架构

    1.1 授权码模式架构图

    image-20210226091245385.png

    流程

    【A服务客户端】需要用到【B服务资源服务】中的资源

    • 第一步:【A服务客户端】将用户自动导航到【B服务认证服务】,这一步用户需要提供一个回调地址,以备 【B服务认证服务】返回授权码使用。
    • 第二步:用户点击授权按钮表示让【A服务客户端】使用【B服务资源服务】,这一步需要用户登录B服务,也就是说用户要事先具有B服务的使用权限。
    • 第三步:【B服务认证服务】生成授权码,授权码将通过第一步提供的回调地址,返回给【A服务客户端】。 注意这个授权码并非通行【B服务资源服务】的通行凭证。
    • 第四步:【A服务认证服务】携带上一步得到的授权码向【B服务认证服务】发送请求,获取通行凭证token。
    • 第五步:【B服务认证服务】给【A服务认证服务】返回令牌token和更新令牌refresh token。

    使用场景

    授权码模式是OAuth2中最安全最完善的一种模式,应用场景最广泛,可以实现服务之间的调用,常见的微信,QQ等第三方登录也可采用这种方式实现。

    二 环境准备

    2.1 构建基于角色的表格

    /*
    SQLyog Ultimate v12.08 (64 bit)
    MySQL - 8.0.16 : Database - security_authority
    *********************************************************************
    */
    
    
    /*!40101 SET NAMES utf8 */;
    
    /*!40101 SET SQL_MODE=''*/;
    
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    /*Table structure for table `sys_permission` */
    
    DROP TABLE IF EXISTS `sys_permission`;
    
    CREATE TABLE `sys_permission` (
      `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
      `permission_NAME` varchar(30) DEFAULT NULL COMMENT '菜单名称',
      `permission_url` varchar(100) DEFAULT NULL COMMENT '菜单地址',
      `parent_id` int(11) NOT NULL DEFAULT '0' COMMENT '父菜单id',
      PRIMARY KEY (`ID`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `sys_permission` */
    
    /*Table structure for table `sys_role` */
    
    DROP TABLE IF EXISTS `sys_role`;
    
    CREATE TABLE `sys_role` (
      `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
      `ROLE_NAME` varchar(30) DEFAULT NULL COMMENT '角色名称',
      `ROLE_DESC` varchar(60) DEFAULT NULL COMMENT '角色描述',
      PRIMARY KEY (`ID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
    
    /*Data for the table `sys_role` */
    
    /*Table structure for table `sys_role_permission` */
    
    DROP TABLE IF EXISTS `sys_role_permission`;
    
    CREATE TABLE `sys_role_permission` (
      `RID` int(11) NOT NULL COMMENT '角色编号',
      `PID` int(11) NOT NULL COMMENT '权限编号',
      PRIMARY KEY (`RID`,`PID`),
      KEY `FK_Reference_12` (`PID`),
      CONSTRAINT `FK_Reference_11` FOREIGN KEY (`RID`) REFERENCES `sys_role` (`ID`),
      CONSTRAINT `FK_Reference_12` FOREIGN KEY (`PID`) REFERENCES `sys_permission` (`ID`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `sys_role_permission` */
    
    /*Table structure for table `sys_user` */
    
    DROP TABLE IF EXISTS `sys_user`;
    
    CREATE TABLE `sys_user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(32) NOT NULL COMMENT '用户名称',
      `password` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
      `status` int(1) DEFAULT '1' COMMENT '1开启0关闭',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    /*Data for the table `sys_user` */
    
    /*Table structure for table `sys_user_role` */
    
    DROP TABLE IF EXISTS `sys_user_role`;
    
    CREATE TABLE `sys_user_role` (
      `UID` int(11) NOT NULL COMMENT '用户编号',
      `RID` int(11) NOT NULL COMMENT '角色编号',
      PRIMARY KEY (`UID`,`RID`),
      KEY `FK_Reference_10` (`RID`),
      CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `sys_role` (`ID`),
      CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `sys_user` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `sys_user_role` */
    
    /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
    /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
    /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
    

    2.2 在MySQL的表中添加几组数据用于测试

    说明:

    • 用户:xiaoming

      密码:199748

      拥有的角色:ROLE_USER,ROLE_PRODUCT

    • 用户:xiaoma

      密码:199748

      拥有的角色:ROLE_USER,ROLE_ORDER

    # sys_user表 password使用加密的方式存储 两者的密码明文为 199748
    +----+----------+--------------------------------------------------------------+--------+
    | id | username | password                                                     | status |
    +----+----------+--------------------------------------------------------------+--------+
    |  4 | xiaoming | $2a$10$9fSu8H/o/qKhRYm8N3IrGePdu5Kj3QNujaW5whHGyoi8ta0Bj4SSG |      1 |
    |  5 | xiaoma   | $2a$10$NJkRs/2AoD1iHlLNe4LwPu8M1ZvmVp4lsCD0QEqCoaRg1Jn2AG2hu |      1 |
    +----+----------+--------------------------------------------------------------+--------+
    
    # sys_role表
    +----+--------------+--------------+
    | ID | ROLE_NAME    | ROLE_DESC    |
    +----+--------------+--------------+
    |  6 | ROLE_USER    | Basic Role   |
    |  7 | ROLE_PRODUCT | Product Role |
    |  8 | ROLE_ORDER   | Order Role   |
    |  9 | ROLE_ADMIN   | Root         |
    +----+--------------+--------------+
    
    # sys_user_role表
    +-----+-----+
    | UID | RID |
    +-----+-----+
    |   4 |   6 |
    |   5 |   6 |
    |   4 |   7 |
    |   5 |   8 |
    +-----+-----+
    

    2.3 创建OAuth2.0表

    /*
    SQLyog Ultimate v12.08 (64 bit)
    MySQL - 8.0.16 : Database - security_authority
    *********************************************************************
    */
    
    
    /*!40101 SET NAMES utf8 */;
    
    /*!40101 SET SQL_MODE=''*/;
    
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    /*Table structure for table `oauth_access_token` */
    
    DROP TABLE IF EXISTS `oauth_access_token`;
    
    CREATE TABLE `oauth_access_token` (
      `token_id` varchar(255) DEFAULT NULL,
      `token` longblob,
      `authentication_id` varchar(255) DEFAULT NULL,
      `user_name` varchar(255) DEFAULT NULL,
      `client_id` varchar(255) DEFAULT NULL,
      `authentication` longblob,
      `refresh_token` varchar(255) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `oauth_access_token` */
    
    /*Table structure for table `oauth_approvals` */
    
    DROP TABLE IF EXISTS `oauth_approvals`;
    
    CREATE TABLE `oauth_approvals` (
      `userId` varchar(255) DEFAULT NULL,
      `clientId` varchar(255) DEFAULT NULL,
      `scope` varchar(255) DEFAULT NULL,
      `status` varchar(10) DEFAULT NULL,
      `expiresAt` datetime DEFAULT NULL,
      `lastModifiedAt` datetime DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `oauth_approvals` */
    
    /*Table structure for table `oauth_client_details` */
    
    DROP TABLE IF EXISTS `oauth_client_details`;
    
    CREATE TABLE `oauth_client_details` (
      `client_id` varchar(255) NOT NULL,
      `resource_ids` varchar(255) DEFAULT NULL,
      `client_secret` varchar(255) DEFAULT NULL,
      `scope` varchar(255) DEFAULT NULL,
      `authorized_grant_types` varchar(255) DEFAULT NULL,
      `web_server_redirect_uri` varchar(255) DEFAULT NULL,
      `authorities` varchar(255) DEFAULT NULL,
      `access_token_validity` int(11) DEFAULT NULL,
      `refresh_token_validity` int(11) DEFAULT NULL,
      `additional_information` varchar(255) DEFAULT NULL,
      `autoapprove` varchar(255) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `oauth_client_details` */
    
    /*Table structure for table `oauth_client_token` */
    
    DROP TABLE IF EXISTS `oauth_client_token`;
    
    CREATE TABLE `oauth_client_token` (
      `token_id` varchar(255) DEFAULT NULL,
      `token` longblob,
      `authentication_id` varchar(255) DEFAULT NULL,
      `user_name` varchar(255) DEFAULT NULL,
      `client_id` varchar(255) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `oauth_client_token` */
    
    /*Table structure for table `oauth_code` */
    
    DROP TABLE IF EXISTS `oauth_code`;
    
    CREATE TABLE `oauth_code` (
      `code` varchar(255) DEFAULT NULL,
      `authentication` varbinary(2550) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `oauth_code` */
    
    /*Table structure for table `oauth_refresh_token` */
    
    DROP TABLE IF EXISTS `oauth_refresh_token`;
    
    CREATE TABLE `oauth_refresh_token` (
      `token_id` varchar(255) DEFAULT NULL,
      `token` longblob,
      `authentication` longblob
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `oauth_refresh_token` */
    
    /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
    /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
    /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
    

    2.4 手动添加客户端信息

    insert into `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('my_server','product_api','$2a$10$CYX9OMv0yO8wR8rE19N2fOaXDJondci5uR68k2eQJm50q8ESsDMlC','read,
    write','client_credentials,implicit,authorization_code,refresh_token,password','http://www.baidu
    .com',NULL,NULL,NULL,NULL,'false');
    # 密码123
    

    三 父工程创建

    3.1 导入pom依赖

     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.2.6.RELEASE</version>
         <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <properties>
        <spring.cloud.version>Hoxton.SR1</spring.cloud.version>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <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>
    

    四 资源模块创建

    4.1 导入pom依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>
        <!--lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    

    4.2 配置文件

    server:
      port: 9002
    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql:///security_authority
        username: root
        password: 199748
      main:
        allow-bean-definition-overriding: true # 这个表示允许我们覆盖OAuth2放在容器中的bean对象
    mybatis:
      type-aliases-package: com.yqj.domain
      configuration:
        map-underscore-to-camel-case: true
    logging:
      level:
        com.yqj: debug
    

    4.3 启动类

    package com.yqj;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * Copyright(C),2019-2021,XXX公司
     * FileName: OAuth2ProductApplication
     * Author: yaoqijun
     * Date: 2021/2/25 15:02
     */
    @SpringBootApplication
    @MapperScan("com.yqj.mapper")
    public class OAuth2ProductApplication {
        public static void main(String[] args) {
            SpringApplication.run(OAuth2ProductApplication.class,args);
        }
    }
    

    4.4 资源controller

    package com.yqj.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * Copyright(C),2019-2021,XXX公司
     * FileName: ProductController
     * Author: yaoqijun
     * Date: 2021/2/25 15:03
     */
    @RestController
    @RequestMapping("/product")
    public class ProductController {
    
        @GetMapping("/findAll")
        public String findAll(){
            return "success findAll...";
        }
    }
    

    4.5 用户和角色类

    将访问的资源作为OAuth2的资源来管理

    • SysUser
    package com.yqj.domain;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import lombok.Data;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    
    import java.util.Collection;
    import java.util.List;
    
    /**
     * Copyright(C),2019-2021,XXX公司
     * FileName: SysUser
     * Author: yaoqijun
     * Date: 2021/2/24 10:14
     */
    @Data
    public class SysUser implements UserDetails {
    
        private Integer id;
        private String username;
        private String password;
        private List<SysRole> roles;
    
        @JsonIgnore
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return roles;
        }
    
        @Override
        public String getPassword() {
            return password;
        }
    
        @Override
        public String getUsername() {
            return username;
        }
    
        @JsonIgnore
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        @JsonIgnore
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
    
        @JsonIgnore
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        @JsonIgnore
        @Override
        public boolean isEnabled() {
            return true;
        }
    }
    
    • SysRole
    package com.yqj.domain;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import lombok.Data;
    import org.springframework.security.core.GrantedAuthority;
    
    /**
     * Copyright(C),2019-2021,XXX公司
     * FileName: SysRole
     * Author: yaoqijun
     * Date: 2021/2/24 10:15
     */
    @Data
    public class SysRole implements GrantedAuthority {
    
        private Integer id;
        private String roleName;
        private String roleDesc;
    
        @JsonIgnore
        @Override
        public String getAuthority() {
            return roleName;
        }
    }
    

    4.6 资源管理配置类

    package com.yqj.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
    import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
    import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
    import org.springframework.security.oauth2.provider.token.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
    
    import javax.sql.DataSource;
    
    /**
     * Copyright(C),2019-2021,XXX公司
     * FileName: OauthSourceConfig
     * Author: yaoqijun
     * Date: 2021/2/25 15:09
     */
    @Configuration
    @EnableResourceServer
    @EnableGlobalMethodSecurity(securedEnabled = true)
    public class OauthSourceConfig extends ResourceServerConfigurerAdapter {
    
        @Autowired
        private DataSource dataSource;
    
        //TokenStore是OAuth2保存token的接口
        @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }
    
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId("product_api") //指定当前资源的id
                    .tokenStore(tokenStore()); //指定保存token的方式
        }
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    //指定不同请求方式访问资源所需要的权限,一般查询是read,其余是write。
                    .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
                    .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
                    .antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
                    .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
                    .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')")
                    .and()
                    .headers().addHeaderWriter((request, response) -> {
                response.addHeader("Access-Control-Allow-Origin", "*");//允许跨域
                if (request.getMethod().equals("OPTIONS")) {//如果是跨域的预检请求,则原封不动向下传达请求头信息
                    response.setHeader("Access-Control-Allow-Methods", request.getHeader("AccessControl-Request-Method"));
                    response.setHeader("Access-Control-Allow-Headers", request.getHeader("AccessControl-Request-Headers"));
                }
            });
    
        }
    }
    

    五 授权模块创建

    5.1 导入pom依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>
        <!--lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    

    5.2 配置文件

    server:
      port: 9001
    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql:///security_authority
        username: root
        password: 199748
      main:
        allow-bean-definition-overriding: true # 这个表示允许我们覆盖OAuth2放在容器中的bean对象
    mybatis:
      type-aliases-package: com.yqj.domain
      configuration:
        map-underscore-to-camel-case: true
    logging:
      level:
        com.yqj: debug
    

    5.3 启动类

    package com.yqj;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * Copyright(C),2019-2021,XXX公司
     * FileName: OAuthServerApplication
     * Author: yaoqijun
     * Date: 2021/2/25 15:15
     */
    @SpringBootApplication
    @MapperScan("com.yqj.mapper")
    public class OAuthServerApplication {
        public static void main(String[] args) {
            SpringApplication.run(OAuthServerApplication.class,args);
        }
    }
    

    5.4 所有认证的代码复制进来

    image-20210226092720244.png

    5.5 SpringSecurity配置类

    package com.yqj.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.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    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.bcrypt.BCryptPasswordEncoder;
    
    /**
     * Copyright(C),2019-2021,XXX公司
     * FileName: WebSecurityConfig
     * Author: yaoqijun
     * Date: 2021/2/25 15:18
     */
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(securedEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private UserDetailsService userDetailsService;
    
        @Bean
        public BCryptPasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .loginProcessingUrl("/login").permitAll()
                    .and()
                    .csrf().disable();
        }
    
        //AuthenticationManager对象在OAuth2认证服务中要使用,提前放入IOC容器中
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    }
    

    5.6 OAuth2授权配置类

    package com.yqj.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.core.userdetails.UserDetailsService;
    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.approval.ApprovalStore;
    import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
    import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
    import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
    import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
    import org.springframework.security.oauth2.provider.token.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
    
    import javax.sql.DataSource;
    
    /**
     * Copyright(C),2019-2021,XXX公司
     * FileName: OauthServerConfig
     * Author: yaoqijun
     * Date: 2021/2/25 15:22
     */
    @Configuration
    @EnableAuthorizationServer
    public class OauthServerConfig extends AuthorizationServerConfigurerAdapter {
        @Autowired
        private DataSource dataSource;
        @Autowired
        private AuthenticationManager authenticationManager;
        @Autowired
        private UserDetailsService userDetailsService;
    
        //从数据库中查询出客户端信息
        @Bean
        public JdbcClientDetailsService clientDetailsService(){
            return new JdbcClientDetailsService(dataSource);
        }
    
        //token保存策略
        @Bean
        public TokenStore tokenStore(){
            return new JdbcTokenStore(dataSource);
        }
    
        //授权信息保存策略
        @Bean
        public ApprovalStore approvalStore(){
            return new JdbcApprovalStore(dataSource);
        }
    
        //授权码模式专用对象
        @Bean
        public AuthorizationCodeServices authorizationCodeServices(){
            return new JdbcAuthorizationCodeServices(dataSource);
        }
    
        //指定客户端登录信息来源
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.withClientDetails(clientDetailsService());
        }
    
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security.allowFormAuthenticationForClients();
            security.checkTokenAccess("isAuthenticated()");
        }
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints
                    .approvalStore(approvalStore())
                    .authenticationManager(authenticationManager)
                    .authorizationCodeServices(authorizationCodeServices())
                    .tokenStore(tokenStore());
        }
    }
    

    六 授权模式测试

    1. 访问地址 http://localhost:9001/oauth/authorize?response_type=code&client_id=my_server 跳转到SpringSecurity默认认证页面,提示用户登录个人账户
    image-20210226093214546.png
    1. 登录成功后询问用户是否给予操作资源的权限,具体给什么权限。Approve是授权,Deny是拒绝
    2. 跳转到回调地址并获取授权码
    image-20210226093410745.png
    1. 使用授权码到服务器申请通行令牌token
    image-20210226093502261.png image-20210226093530522.png
    1. 携带token访问资源
    image-20210226093627126.png

    相关文章

      网友评论

        本文标题:SpringSecurity结合OAuth2实现第三方授权

        本文链接:https://www.haomeiwen.com/subject/ovqmfltx.html