最近在学习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服务)”、“用户”、“认证服务器”、“资源服务器”等部分。认证流程如下图:
A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
接下来我们就来写代码,首先新建一个SpringBoot工程
父工程不引入任何依赖
创建过程不再赘述,创建完之后项目结构如下:
接下来 我们在父工程中配置依赖管理
<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
这里选择Cloud Oauth2 的依赖
接下来我们创建一个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 项目结构的如下所示:
这个项目的端口是默认的8080
之后会附上源码
之后启动oauth-server
启动项目之后说无法访问 javax.servlet.Filter
之后我在改子项目中添加对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
访问之后进入登陆页面:
我们输入用户名密码:admin/123456
进入到这个页面:
我们选择approve点击Authorize认证
认证之后
这个就是code
我们打开postman用post方式获取access_token
如果code写错会报错
这个client就是配置的client_id,secret就是配置的secret,返回access_token
至此基于内存的oauth2实现完成,我们也获取到了 token