展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

权限认证(三):OAuth2认证服务器

  • 创建父工程mengxuegu-cloud-oauth2-parent
    <packaging>pom</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>
    <properties>
        <spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <mybatis-plus.version>3.2.0</mybatis-plus.version>
        <druid.version>1.1.12</druid.version>
        <kaptcha.version>2.3.2</kaptcha.version>
        <fastjson.version>1.2.8</fastjson.version>
        <commons-lang.version>2.6</commons-lang.version>
        <commons-collections.version>3.2.2</commons-collections.version>
        <commons-io.version>2.6</commons-io.version>
        <!-- 定义版本号, 子模块直接引用-->
        <mengxuegu-security.version>1.0-SNAPSHOT</mengxuegu-security.version>
    </properties>
    <!--依赖声明-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <!--maven不支持多继承,使用import来依赖管理配置-->
                <scope>import</scope>
            </dependency>
            <!--mybatis-plus启动器-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
            <!--druid连接池-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!-- kaptcha 用于图形验证码 -->
            <dependency>
                <groupId>com.github.penggle</groupId>
                <artifactId>kaptcha</artifactId>
                <version>${kaptcha.version}</version>
            </dependency>
            <!-- 工具类依赖 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>
            <dependency>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
                <version>${commons-lang.version}</version>
            </dependency>
            <dependency>
                <groupId>commons-collections</groupId>
                <artifactId>commons-collections</artifactId>
                <version>${commons-collections.version}</version>
            </dependency>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>${commons-io.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!--springboot 打包插件-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
  • 创建子模块mengxuegu-cloud-oauth2-base
    <dependencies>
        <!--类中setter/getter,使用注解-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- 工具类依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>
    </dependencies>
  • resource路径下编写logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--梦学谷 www.mengxuegu.com -->
<configuration>
    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </layout>
    </appender>

    <root level="info">
        <appender-ref ref="stdout" />
    </root>
</configuration> 
  • 在com.mengxuegu.base.result路径下编写MengxueguResult
@Data
public class MengxueguResult implements Serializable {
    // 响应业务状态
    private Integer code;
    // 响应消息
    private String message;
    // 响应中的数据
    private Object data;
    public MengxueguResult() {
    }
    public MengxueguResult(Object data) {
        this.code = 200;
        this.message = "OK";
        this.data = data;
    }
    public MengxueguResult(String message, Object data) {
        this.code = 200;
        this.message = message;
        this.data = data;
    }
    public MengxueguResult(Integer code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }
    public static MengxueguResult ok() {
        return new MengxueguResult(null);
    }
    public static MengxueguResult ok(String message) {
        return new MengxueguResult(message, null);
    }
    public static MengxueguResult ok(Object data) {
        return new MengxueguResult(data);
    }
    public static MengxueguResult ok(String message, Object data) {
        return new MengxueguResult(message, data);
    }
    public static MengxueguResult build(Integer code, String message) {
        return new MengxueguResult(code, message, null);
    }
    public static MengxueguResult build(Integer code, String message, Object data) {
        return new MengxueguResult(code, message, data);
    }
    public String toJsonString() {
        return JSON.toJSONString(this);
    }
    /**
     * JSON字符串转成 MengxueguResult 对象
     * @param json
     * @return
     */
    public static MengxueguResult format(String json) {
        try {
            return JSON.parseObject(json, MengxueguResult.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • 创建子模块mengxuegu-cloud-oauth2-server
    <dependencies>
        <dependency>
            <groupId>com.mengxuegu</groupId>
            <artifactId>mengxuegu-cloud-oauth2-base</artifactId>
            <version>${mengxuegu-security.version}</version>
        </dependency>
        <!--spring mvc相关的-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Spring Security、OAuth2 和JWT等 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <!-- springboot 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!--热部署 ctrl+f9-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!--启动类-->
                <configuration>
                    <mainClass>com.mengxuegu.oauth2.AuthServerApplication</mainClass>
                </configuration>

            </plugin>
        </plugins>
    </build>
  • 编写application.yml
server:
  port: 8090
  servlet:
    context-path: /auth   # 应用名 localhost:8090/auth
  • com.mengxuegu.oauth2路径下编写启动类
@SpringBootApplication
public class AuthServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(AuthServerApplication.class, args);
    }
}
  • 编写配置类
@Configuration
@EnableAuthorizationServer // 开启了认证服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;
    /**
     * 配置被允许访问此认证服务器的客户端信息
     * 1.内存方式
     * 2. 数据库方式
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 内存方式管理客户端信息
        clients.inMemory()
                .withClient("mengxuegu-pc") // 客户端id
                .secret(passwordEncoder.encode("mengxuegu-secret")) // 客户端密码,需加密
                .resourceIds("product-server") // 资源id,可理解为微服务名称,表示可访问哪些微服务
                .authorizedGrantTypes("authorization_code", "password", "implicit", "client_credentials", "refresh_token")  //认证模式
                .scopes("all") // 授权范围标识,哪部分资源可访问(all只是标识,不是说所有资源)
                .autoApprove(false) // false 跳到一个授权页面手动点击授权,true不需要手动点授权,直接响应一个授权码
                .redirectUris("http://www.mengxuegu.com/") // 客户端回调地址
            ;
    }
}

@Configuration
public class SpringSecurityBean {
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password(passwordEncoder.encode("1234"))
                .authorities("product");
    }
}
  • 测试
# 浏览器访问
http://localhost:8090/auth/oauth/authorize?client_id=mengxuegu-pc&response_type=code
# 进入用户认证页面,输入用户名和密码
# 选择将哪些资源开放给第三方客户端(之前在配置类中配置了autoApprove(false)表示手动选择要开放的资源)
  • 获取授权码
http://localhost:8090/auth/oauth/authorize?client_id=mengxuegu-pc&response_type=code





  • 密码模式
# SpringSecurityConfig类中添加如下
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

# AuthorizationServerConfig类中添加如下
    @Autowired // SpringSecurityConfig添加到容器中了
    private AuthenticationManager authenticationManager;
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 密码模式要设置认证管理器
        endpoints.authenticationManager(authenticationManager);
    }

  • postman测试

  • 简单模式

# 浏览器访问
http://localhost:8090/auth/oauth/authorize?client_id=mengxuegu-pc&response_type=token

  • 客户端模式

  • 使用redis管理访问令牌

# 添加依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

# 编写TokenConfig
@Configuration
public class TokenConfig {
    @Autowired   //采用redis管理token
    private RedisConnectionFactory redisConnectionFactory;
    @Bean
    public TokenStore tokenStore() {
        // redis 管理令牌
        return new RedisTokenStore(redisConnectionFactory);
    }
}

# AuthorizationServerConfig配置如下
    @Autowired // token管理方式,在TokenConfig类中已对添加到容器中了
    private TokenStore tokenStore;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 令牌的管理方式
        endpoints.tokenStore(tokenStore);
    }
  • 本地启动redis测试
  • 由于我本地没有安装redis
# yml中配置如下
spring:
  redis:
    database: 0
    host: 124.222.5.107
    port: 6379
    password: 123456
#    client-type: lettuce
#    lettuce:
#      pool:
#        max-active: 8
#        max-wait: -1ms
#        max-idle: 8
#        min-idle: 0
    timeout: 2000
  • 启动报错
Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 124.222.5.107:6379

---分割线

  • 使用redis存储访问令牌参考
# pom
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-pool2</artifactId>
</dependency>

# yml
spring:
  application:
    name: security-demo
  redis:
    host: 192.168.1.102
    port: 6379
    # password: 没有不用写
    lettuce:
      # 连接池配置
      pool:
        # 连接池中的最小空闲连接,默认 0
        min-idle: 0
        # 连接池中的最大空闲连接,默认 8
        max-idle: 8
        # 连接池最大阻塞等待时间(使用负值表示没有限制),默认 -1ms
        max-wait: -1ms
        # 连接池最大连接数(使用负值表示没有限制),默认 8
        max-active: 8

# 编写TokenConfig
@Configuration
public class TokenConfig {
    @Autowired   //采用redis管理token
    private RedisConnectionFactory redisConnectionFactory;
    @Bean
    public TokenStore tokenStore() {
        // redis 管理令牌
        return new RedisTokenStore(redisConnectionFactory);
    }
}

# AuthorizationServerConfig配置如下
    @Autowired // token管理方式,在TokenConfig类中已对添加到容器中了
    private TokenStore tokenStore;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 令牌的管理方式
        endpoints.tokenStore(tokenStore);
    }
  • 测试

posted @ 2022-03-28 10:48  DogLeftover  阅读(86)  评论(0编辑  收藏  举报