1、创建Maven项目
(1)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.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cmxy</groupId>
<artifactId>oauth2-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>oauth2-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Security、OAuth2 和JWT相关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!--Web相关-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--Mysql连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
(2)项目结构
2、代码实现(暂时只是最简单的实现,后面会不断补充)
(1)创建认证服务器配置类
package com.cmxy.oauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
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.stereotype.Component;
/**
* 认证服务器配置类
* 作用:配置哪些客户端可以访问当前配置服务器
*/
@Component
@EnableAuthorizationServer //标记为认证服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 配置可以访问此认证服务器的客户端信息
* 可以采用:JDBC或者内存的方式(原理其实差不太多)
* 为了方便暂时使用基于内存的形式存储客户端信息
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()//基于内存的模式
.withClient("client")//客户端ID
.secret(passwordEncoder.encode("123456"))//客户端秘钥,这里一定要加密。SpringSecurity 5.0之后规定密码必须加密。
.resourceIds("product")//能访问的资源ID
.scopes("user")//能访问的范围
//授权方式:即当前认证服务器支持的授权方式分贝为 授权码模式、密码模式、客户端模式、简易模式、刷新Token
.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
.autoApprove(false)//是否自动授权,一般设置为false表示需要用户手动授权
.redirectUris("www.baidu.com");//重定向路径
}
}
(2)创建Spring Security配置类
package com.cmxy.oauth2.server.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
@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");
}
}
(3)配置加密方式(SpringSecurity5.0之后,要求必须密码加密)
package com.cmxy.oauth2.server.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SpringSecurityBean {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
3、接口测试
首先测试的是授权码模式
授权码模式:
功能最完整,流程最严密的授权模式。国内各大服务提供商(微信、QQ、微 博、淘宝 、百度)都采用此模式进行授权。可以确定是用户真正同意授权;而且令牌是认证服务器发放给第三方应 用的服务器,而不是浏览器上。
(1)在浏览器输入url:http://localhost:8080/oauth/authorize?client_id=client&response_type=code
其中:client_id 为配置类中配置的,响应的类型为授权码
(2)此时因为之前未登录所以会跳转到登陆页
注意这里的账号密码是资源拥有者的,不是客户端的!!!在本demo中,账号为admin 密码123456
登陆成功后跳转到授权页面(是不是有点类似于微信的授权)
(3)选择授权,则会跳转到之前配置的重定向路径,也就是百度
注意此时是包含了授权码,最后拿授权码去换token,每个授权码只能使用一次。
(4)获取Token
最后则携带Token去请求对应资源。至此最复杂的授权码模式已经完成
未完待续。。。