一、构建授权服务器:内存模式 (学习视频)
1、pom依赖
1.1、Spring Security Oauth2
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
1.2、Spring Cloud
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
2、创建AuthorizationServer、TokenConfig、WebSecurityConfig
2.1、创建AuthorizationServer类继承AuthorizationServerConfigurerAdapter
描述:该类需要重写父类的这三个方法,顺序AuthorizationServerSecurityConfigurer(配置客户端详细信息,客户端标识、客户端秘钥、资源列表等等) -> AuthorizationServerEndpointsConfigurer(管理令牌:令牌生成和存储) -> ClientDetailsServiceConfigurer (用来配置令牌端点的安全约束:拦截控制)
// 用来配置客户端详情服务(ClientDetailsService),客户端详情信息在 这里进行初始化,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息。
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {}
// 用来配置令牌(token)的访问端点和令牌服务(token services)。
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {}
// 用来配置令牌端点的安全约束
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {}
package com.cyun.security.oauth2.config;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
/**
* 授权服务器配置
*
* @author He PanFu
* @date 2021-12-19 17:55:23
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Autowired private TokenStore tokenStore;
@Autowired private ClientDetailsService clientDetailsService;
@Autowired private AuthenticationManager authenticationManager;
@Autowired private PasswordEncoder passwordEncoder;
/**
* 令牌服务
* @return
*/
@SuppressWarnings({"All"})
@Bean
public AuthorizationServerTokenServices tokenService() {
DefaultTokenServices service = new DefaultTokenServices();
// 是否刷新令牌
service.setSupportRefreshToken(true);
// 令牌存储策略
service.setTokenStore(tokenStore);
// 令牌默认有效期2小时
service.setAccessTokenValiditySeconds(7200);
// 刷新令牌默认有效期3天
service.setRefreshTokenValiditySeconds(259200);
return service;
}
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
//设置授权码模式的授权码如何 存取,暂时采用内存方式
return new InMemoryAuthorizationCodeServices();
}
/**
* 配置客户端详细信息
* TODO 将来改成在数据库中
*
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 暂时使用in‐memory存储
clients.inMemory()
// 客户端标识
.withClient("c1")
// 客户端秘钥
.secret(passwordEncoder.encode("secret"))
// 资源列表
.resourceIds("res1")
// 允许授权的五种类型
.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
// 允许的授权范围
.scopes("all")
// false=跳转到授权页面,true=直接方法令牌
.autoApprove(false)
// 加上验证回调地址
.redirectUris("http://www.baidu.com");
}
/**
* 管理令牌:用来配置令牌(token)的访问端点和令牌服务(token services)。
*
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 密码模式
endpoints.authenticationManager(authenticationManager)
// 授权码模式
.authorizationCodeServices(authorizationCodeServices())
.tokenServices(tokenService())
// 支持的请求
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
/**
* 用来配置令牌端点的安全约束
* 拦截控制
*
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
/*
* /oauth/authorize:授权端点。
* /oauth/token:令牌端点。
* /oauth/confirm_access:用户确认授权提交端点。
* /oauth/error:授权服务错误信息端点。
* /oauth/check_token:用于资源服务访问的令牌解析端点。
* /oauth/token_key:提供公有密匙的端点,如果你使用JWT令牌的话。
*/
// token_key公开
security.tokenKeyAccess("permitAll()")
// check_token公开
.checkTokenAccess("permitAll()")
.allowFormAuthenticationForClients();
// clientCredentialsTokenEndpointFilter(security);
// security.addTokenEndpointAuthenticationFilter(clientCredentialsTokenEndpointFilter(null));
}
}
2.2、创建TokenConfig类
package com.cyun.security.oauth2.config;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
/**
* 自定义 TokenConfig 配置
*
* @author He PanFu
* @date 2021-12-19 17:55:23
*/
@Configuration
@RequiredArgsConstructor
public class TokenConfig {
/**
* token 保存正在内存中
* @return
*/
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
2.3、创建WebSecurityConfig
package com.cyun.security.oauth2.config;
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.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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* Spring Security 配置
*
* @author He PanFu
* @date 2021-12-19 17:55:23
*/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true,jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
String encode = passwordEncoder().encode("1");
auth.inMemoryAuthentication()
.withUser("root").password(encode).roles("ADMIN", "DBA");
}
/**
* 安全拦截机制(最重要)
*
* @param http HttpSecurity安全配置
* @throws Exception 异常
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/r/r1").hasAnyAuthority("p1")
.antMatchers("/login").permitAll()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated()
.and().formLogin();
}
}
二、启动服务,授权(安全性由高到低)
1、授权码模式(authorization_code)
获取授权码:localhost:7103/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com
授权码登录:http://localhost:7103/oauth/token?client_id=c1&redirect_uri=http://www.baidu.com&client_secret=secret&grant_type=authorization_code&code=7qw29a
结果展示:
2、简化模式(token):授权后直接登录,获取到参数access_token、token_type、expires_in
URL:http://localhost:7103/oauth/authorize?client_id=c1&response_type=token&scope=all&redirect_uri=http://www.baidu.com
结果展示:
3、账号密码模式(password)
URL:http://localhost:7103/oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=root&password=1
结果展示:
4、客户端模式(client_credentials)
URL:http://localhost:7103/oauth/token?client_id=c1&client_secret=secret&grant_type=client_credentials
结果展示:
5、刷新token模式(refresh_token)。当token过期后,调用次接口获取新token。
URL:http://localhost:7103/oauth/token?grant_type=refresh_token&refresh_token=2ae3ca8f-0cff-4e7d-ad7c-b193a0e7aceb&client_id=c1&client_secret=secret