一、介绍
OAuth2是目前最流行的授权机制,用来授权第三方应用,获取用户数据。允许用户授权B应用不提供帐号密码的方式去访问该用户在A应用服务器上的某些特定资源。
资源所有者(Resource Owner):拥有受保护资源(如用户资料、照片、视频等)的用户。
客户端(Client):想要访问资源所有者资源的第三方应用程序。
授权服务器(Authorization Server):处理客户端的授权请求并发放访问令牌。
资源服务器(Resource Server):存储受保护的资源,并在访问令牌的授权下提供资源。
访问令牌(Access Token):授权服务器发放的用于访问资源的令牌。
回调URL(Callback URL):客户端在申请授权时提供的 URL,用于在授权成功后将访问令牌发送给客户端。
二、oauth2.0四个角色
资源所有者(Resource Owner):这是拥有受保护资源的用户。例如,一个用户可能有存储在云服务提供商的文件。
授权服务器(Authorization Server):这是处理请求和响应的中央服务器。它授权客户端访问资源所有者的资源。
资源服务器(Resource Server):这是存储和提供受保护资源的服务器。例如,云服务提供商可能会有一个资源服务器,它存储用户的文件。
客户端(Client):这是想要访问资源所有者的资源的客户端应用程序。例如,一个云存储同步工具的移动应用程序可能会扮演客户端的角色。
三、 四种授权模式
授权码(Authorization Code):
客户端向资源所有者请求授权。
资源所有者同意授权,并返回一个授权码。
客户端使用授权码向授权服务器请求访问令牌。
授权服务器验证授权码,并发放访问令牌。
隐藏式(Implicit):
客户端直接向资源服务器请求受保护的资源,并在 URL 中携带访问令牌。
资源服务器验证访问令牌,并响应请求。
密码式(Password):
客户端使用资源所有者的用户名和密码向授权服务器请求访问令牌。
授权服务器验证用户名和密码,并发放访问令牌。
客户端凭证(Client Credentials):
客户端使用其客户端凭证(如客户端ID和客户端密钥)向授权服务器请求访问令牌。
授权服务器验证客户端凭证,并发放访问令牌。
在实际应用中,根据应用程序的需求和安全性要求,开发人员可以选择适当的授权模式。对于Web应用程序,通常使用授权码或隐藏式;对于移动应用程序,通常使用隐藏式或客户端凭证。密码式通常不推荐使用,因为它可能会导致密码泄露。
四、OAUTH2的spring cloud 微服务单点登录
用户:就是注册的用户
客户端:就是我们的前端项目
授权服务器:我们可以专门在后台创建一个专门管授权的微服务
资源微服务:像其他的订单微服务,什么搜索微服务拉都可以看做用户能够访问的资源
五、 spring cloud alibaba 使用oauth2
- 创建父项目
- 启动nacos
3. 导入依赖
XML
<!-- 添加 OAuth2 依赖 -->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
<!-- 添加 JWT 依赖 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
**六、**授权码模式测试
1. 启动类中加入BCryptPasswordEncoder
java
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
2. 写一个OauthConfig配置类
java
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;
import javax.annotation.Resource;
@Configuration
@EnableAuthorizationServer
public class MyOauthConfig extends AuthorizationServerConfigurerAdapter {
@Resource
private BCryptPasswordEncoder bCryptPasswordEncoder;
/*
* authorization_code 授权码模式
* password 密码模式
* client_credentials 客户端模式
* implicit 简单模式
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 将客户端的信息配置在内存中
clients.inMemory()
.withClient("admin")// 客户端id
.secret(bCryptPasswordEncoder.encode("123456"))// 客户端密码
.redirectUris("https://www.baidu.com")// 客户端重定向地址
.scopes("all")// 客户端授权范围
.authorities("all")// 客户端权限
.authorizedGrantTypes("authorization_code")// 客户端授权类型
.autoApprove(true);// 是否自动授权
}
}
3.写一个security配置类
java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.bcrypt.BCryptPasswordEncoder;
import javax.annotation.Resource;
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 允许访问"/oauth/**"路径的所有请求
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
// 其他所有请求需要进行身份验证
.anyRequest().authenticated()
// 允许表单登录
.and()
.formLogin().permitAll();
// 禁用CSRF保护
http.csrf().disable();
}
// 自定义用户的信息
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
// 设置用户名为"root"
.withUser("root")
// 设置密码为"123456",并使用BCryptPasswordEncoder进行加密
.password(bCryptPasswordEncoder.encode("123456"))
// 设置角色为"admin"
.roles("admin");
}
}
4. 配置端口号
5. 申请授权码
http://localhost:8086/oauth/authorize?response_type=code&client_id=admin&scop=all
输入之后回车会跳转到登录页面
输入账号密码
账号密码就是这个
输入账号密码后跳转
6. 根据授权码生成token
七、简单模式测试
1. 修改OauthConfig的配置类
2. 访问地址
http://localhost:8086/oauth/authorize?response_type=token&client_id=admin&scope=all
八、客户端模式测试
1. 修改OauthConfig的配置类
2. 访问
九、密码模式测试
1. 修改SecurityConfig的配置类
java
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.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.crypto.bcrypt.BCryptPasswordEncoder;
import javax.annotation.Resource;
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 允许访问"/oauth/**"路径的所有请求
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
// 其他所有请求需要进行身份验证
.anyRequest().authenticated()
// 允许表单登录
.and()
.formLogin().permitAll();
// 禁用CSRF保护
http.csrf().disable();
}
// 自定义用户的信息
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
// 设置用户名为"root"
.withUser("root")
// 设置密码为"123456",并使用BCryptPasswordEncoder进行加密
.password(bCryptPasswordEncoder.encode("123456"))
// 设置角色为"admin"
.roles("admin");
}
// 获取认证管理器
@Bean
public AuthenticationManager geAuthManager() throws Exception {
return super.authenticationManagerBean();
}
}
2. 修改OauthConfig配置类
java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import javax.annotation.Resource;
@Configuration
@EnableAuthorizationServer
public class MyOauthConfig extends AuthorizationServerConfigurerAdapter {
@Resource
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Resource
private AuthenticationManager authenticationManager;
/*
* authorization_code 授权码模式
* password 密码模式
* client_credentials 客户端模式
* implicit 简单模式
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 将客户端的信息配置在内存中
clients.inMemory()
.withClient("admin")// 客户端id
.secret(bCryptPasswordEncoder.encode("123456"))// 客户端密码
.redirectUris("https://www.baidu.com")// 客户端重定向地址
.scopes("all")// 客户端授权范围
.authorities("all")// 客户端权限
.authorizedGrantTypes("password")// 客户端授权类型
.autoApprove(true);// 是否自动授权
}
// 配置授权服务器的端点
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
3.访问
4. 不用输入第三方的用户名和密码
修改OauthConfig配置类
java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import javax.annotation.Resource;
@Configuration
@EnableAuthorizationServer
public class MyOauthConfig extends AuthorizationServerConfigurerAdapter {
@Resource
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Resource
private AuthenticationManager authenticationManager;
/*
* authorization_code 授权码模式
* password 密码模式
* client_credentials 客户端模式
* implicit 简单模式
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 将客户端的信息配置在内存中
clients.inMemory()
.withClient("admin")// 客户端id
.secret(bCryptPasswordEncoder.encode("123456"))// 客户端密码
.redirectUris("https://www.baidu.com")// 客户端重定向地址
.scopes("all")// 客户端授权范围
.authorities("all")// 客户端权限
.authorizedGrantTypes("password")// 客户端授权类型
.autoApprove(true);// 是否自动授权
}
/*
* 配置授权服务器的端点
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
/*
* 配置授权服务器的安全性
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients() // 允许客户端使用表单进行身份验证
.checkTokenAccess("permitAll()") // 检查访问令牌的访问权限,允许所有
.tokenKeyAccess("permitAll()"); // 检查访问令牌密钥的访问权限,允许所有
}
}
5. 校验token
路径
localhost:8086/oauth/check_token?
6. 手动生成Token,解析Token
java
package org.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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;
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.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import javax.annotation.Resource;
@Configuration
@EnableAuthorizationServer
public class MyOauthConfig extends AuthorizationServerConfigurerAdapter {
@Resource
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Resource
private AuthenticationManager authenticationManager;
/*
* authorization_code 授权码模式
* password 密码模式
* client_credentials 客户端模式
* implicit 简单模式
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 将客户端的信息配置在内存中
clients.inMemory()
.withClient("admin")// 客户端id
.secret(bCryptPasswordEncoder.encode("123456"))// 客户端密码
.redirectUris("https://www.baidu.com")// 客户端重定向地址
.scopes("all")// 客户端授权范围
.authorities("all")// 客户端权限
.authorizedGrantTypes("password")// 客户端授权类型
.autoApprove(true);// 是否自动授权
}
// * 配置授权服务器的端点
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(getTokenStore()) // token存储的地方
.accessTokenConverter(jwtAccessTokenConverter());// 生成token的bean 解析token的bean
}
// * 配置授权服务器的安全性
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients() // 允许客户端使用表单进行身份验证
.checkTokenAccess("permitAll()") // 检查访问令牌的访问权限,允许所有
.tokenKeyAccess("permitAll()"); // 检查访问令牌密钥的访问权限,允许所有
}
@Bean
public TokenStore getTokenStore(){
return new JwtTokenStore(jwtAccessTokenConverter());
}
/* *
* 生成token的bean
* 解析token的bean*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey("asd");
return jwtAccessTokenConverter;
}
}
7.自定义登陆
修改Securityconfig类
java
package org.example.config;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.entity.ResponseMsg;
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.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.crypto.bcrypt.BCryptPasswordEncoder;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().loginProcessingUrl("/userlogin")
.successHandler((httpServletRequest, httpServletResponse, authentication) -> {
String username = httpServletRequest.getParameter("username");
String password = httpServletRequest.getParameter("password");
HttpRequest post = HttpUtil.createPost("http://localhost:8086/oauth/token");
post.form("grant_type","password");
post.form("client_id","admin");
post.form("client_secret","123456");
post.form("username",username);
post.form("password",password);
HttpResponse execute = post.execute();// 发送请求
String body = execute.body();
JSONObject entries = JSONUtil.parseObj(body);
Object accessToken = entries.get("access_token");
printJsonData(httpServletResponse,new ResponseMsg(200,"成功",accessToken));
});
// 允许访问"/oauth/**"路径的所有请求
http.authorizeRequests()
.antMatchers("/userlogin","/oauth/**").permitAll()
// 其他所有请求需要进行身份验证
.anyRequest().authenticated()
// 允许表单登录
.and()
.formLogin().permitAll();
// 禁用CSRF保护
http.csrf().disable();
}
// 自定义用户的信息
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
// 设置用户名为"root"
.withUser("root")
// 设置密码为"123456",并使用BCryptPasswordEncoder进行加密
.password(bCryptPasswordEncoder.encode("123456"))
// 设置角色为"admin"
.roles("admin");
}
// 获取认证管理器
@Bean
public AuthenticationManager geAuthManager() throws Exception {
return super.authenticationManagerBean();
}
public void printJsonData(HttpServletResponse response, ResponseMsg responseMsg) {
try {
response.setContentType("application/json;charset=utf8");
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(responseMsg);
PrintWriter writer = response.getWriter();
writer.print(s);
writer.flush();
writer.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
访问
8.order
写一个order
写一个配置类
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(jsr250Enabled = true,prePostEnabled = true,securedEnabled=true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 其他所有请求需要进行身份验证
.anyRequest().authenticated()
// 允许表单登录
.and()
.formLogin().permitAll();
// 禁用CSRF保护
http.csrf().disable();
}
@Bean
public TokenStore getTokenStore(){
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey("root");
return jwtAccessTokenConverter;
}
}
controller
java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping
public String test(){
return "成功";
}
}
resouce配置文件
测试