最近在学习Spring Security 和 Spring Cloud Security ,这个模块还是比较复杂的,我一般学习的方法是先写一个demo,跑通然后在管细节。上一篇我们 我们也是研究了Spring Security (Spring Security 实现OAuth2.0实现授权服务--基础版 地址: 感兴趣的可以去看一下),上一篇由于一些原因没有获得token,这一片我们也是在借鉴了前人的基础上使用Spring Cloud Security 实现OAuth 然后获得token

借鉴的文章是: 感谢这篇作者

 

        先声明oauth2是一种协议规范,spring-security-oauth2是对他的一种实现。其次,还有shiro实现,自己根据规范编写代码的实现方式。主流的qq,微信等第三方授权登录方式都是基于oauth2实现的。
oauth2的认证方式有授权码,简单,账户密码,客户端等方式,具体请自行百度不做过多的阐述。 本文基于授权码方式实现
oauth生态设计的范围很大,可以说是一种解决方案,它有“第三方客户端(web服务,APP服务)”、“用户”、“认证服务器”、“资源服务器”等部分。认证流程如下图:

springcloud oauth2 密码错误返回_ci

 

A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。

(C)客户端使用上一步获得的授权,向认证服务器申请令牌。

(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。

(E)客户端使用令牌,向资源服务器申请获取资源。

(F)资源服务器确认令牌无误,同意向客户端开放资源。

接下来我们就来写代码,首先新建一个SpringBoot工程

springcloud oauth2 密码错误返回_ci_02

 

springcloud oauth2 密码错误返回_spring_03

父工程不引入任何依赖

springcloud oauth2 密码错误返回_客户端_04

创建过程不再赘述,创建完之后项目结构如下:

springcloud oauth2 密码错误返回_ci_05

接下来 我们在父工程中配置依赖管理

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.RC2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.9.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

添加依赖管理后 父工程的pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.taoj.demo</groupId>
    <artifactId>spring-cloud-oauth-demo07</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-cloud-oauth-demo07</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </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>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.RC2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.9.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

接下来我们新建一个Module oauth-server

springcloud oauth2 密码错误返回_ci_06

springcloud oauth2 密码错误返回_spring_07

这里选择Cloud Oauth2 的依赖

springcloud oauth2 密码错误返回_客户端_08

springcloud oauth2 密码错误返回_客户端_09

接下来我们创建一个config包,因为,我们认证之前需要先校验用户的账户密码是否正确,所以我们先配置WebSecurityConfig拦截:

package com.taoj.deo.oauthserver.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
//对全部方法进行验证
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    BCryptPasswordEncoder passwordEncoder;

    /**
     * 配置内存登陆用户认证
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.inMemoryAuthentication()
                .withUser("admin").password(passwordEncoder.encode("123456")).roles("ADMIN")
                .and()
                .withUser("user").password(passwordEncoder.encode("123456")).roles("USER");
    }

}

在config方法里,我们在内存中,配置了两个用户,这里注意密码用了BCryptPasswordEncoder进行加密,在springboot2.x中不加密会报错的。
(4)到这里,用户验证已经完成,我们创建AuthConfig配置认证拦截处理:

package com.taoj.deo.oauthserver.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

@Configuration
//开启认证服务
@EnableAuthorizationServer
public class AuthConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * 配置密码加密 springboot2.x需要配置
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception{
        clients.inMemory()
                .withClient("client")
                .secret(passwordEncoder().encode("secret"))
                .authorizedGrantTypes("authorization_code")
                .scopes("app")
                .redirectUris("http://127.0.0.1:8080/say");
    }


}

需要添加 @EnableAuthorizationServer注解开启认证服务,注入加密用的BCryptPasswordEncoder实例。然后,配置需要认证的客户端,
这里需要细说一下,首先是client_id代表是哪个客户端也就是哪个APP或者web服务需要认证的,然后是客户端的secret秘钥需要加密,
authorizedGrantTypes授权方式指的是授权码,简单,客户端,账户密码等,这里使用的是授权码(authorization_code),然后是scopes范围,
redirectUris重定向地址,就是你的登录地址,授权后跳转的地址。

这里的redirectUris 我重定向到了一个 oauth-client项目中的Controller

oauth-client 项目结构的如下所示:

springcloud oauth2 密码错误返回_spring_10

这个项目的端口是默认的8080

之后会附上源码

之后启动oauth-server

启动项目之后说无法访问 javax.servlet.Filter 

springcloud oauth2 密码错误返回_spring_11

 

之后我在改子项目中添加对spring-boot-starter-web 的依赖之后

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

添加以来之后 重启 正常

之后在浏览器中访问 http://localhost:9000/oauth/authorize?client_id=client&response_type=code

访问之后进入登陆页面:

springcloud oauth2 密码错误返回_spring_12

我们输入用户名密码:admin/123456

进入到这个页面:

springcloud oauth2 密码错误返回_spring_13

我们选择approve点击Authorize认证

springcloud oauth2 密码错误返回_客户端_14

认证之后 

springcloud oauth2 密码错误返回_客户端_15

这个就是code
 

我们打开postman用post方式获取access_token

springcloud oauth2 密码错误返回_ci_16

 

如果code写错会报错

springcloud oauth2 密码错误返回_spring_17

这个client就是配置的client_id,secret就是配置的secret,返回access_token

至此基于内存的oauth2实现完成,我们也获取到了 token