<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- springboot整合freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-->spring-boot 整合security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- spring-cloud-starter-oauth2 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
二、授权中心案例代码
Oauth2相关配置:
/**
* @author Mr.Zheng
* @Program: parent
* @Description: 配置授权中心信息
* @date 2020-05-03 13:21
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
/**
* accessToken有效期 两小时
*/
private int accessTokenValiditySeconds = 7200;
/**
* refreshToken有效期 两小时
*/
private int refreshTokenValiditySeconds = 7200;
/**
* 添加商户信息
*
* @param clients 商户
* @throws Exception 异常
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//商户id
.withClient("client_1")
//商户secret
.secret(passwordEncoder().encode("123456"))
//回调地址
.redirectUris("https://www.baidu.com/")
/* OAuth2为我们提供了四种授权方式:
* 1、授权码模式(authorization code)用在客户端与服务端应用之间授权
* 2、简化模式(implicit)用在移动app或者web app(这些app是在用户的设备上的,如在手机上调起微信来进行认证授权)
* 3、密码模式(resource owner password credentials)应用直接都是受信任的(都是由一家公司开发的)
* 4、客户端模式(client credentials)用在应用API访问
*/
.authorizedGrantTypes("password", "client_credentials", "refresh_token", "authorization_code")
//授权范围
.scopes("all")
//accessToken有效期
.accessTokenValiditySeconds(accessTokenValiditySeconds)
//refreshToken有效期
.refreshTokenValiditySeconds(refreshTokenValiditySeconds);
}
/**
* 设置token类型
* @param endpoints
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager())
.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);
endpoints.authenticationManager(authenticationManager());
endpoints.userDetailsService(userDetailsService());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
// 允许表单认证
oauthServer.allowFormAuthenticationForClients();
// 允许check_token访问
oauthServer.checkTokenAccess("permitAll()");
}
@Bean
AuthenticationManager authenticationManager() {
AuthenticationManager authenticationManager = new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return daoAuhthenticationProvider().authenticate(authentication);
}
};
return authenticationManager;
}
@Bean
public AuthenticationProvider daoAuhthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService());
daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return daoAuthenticationProvider;
}
/**
* 设置添加用户信息,正常应该从数据库中读取
*
* @return UserDetailsService
*/
@Bean
UserDetailsService userDetailsService() {
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
userDetailsService.createUser(User.withUsername("user_1").password(passwordEncoder().encode("123456"))
.authorities("ROLE_USER").build());
userDetailsService.createUser(User.withUsername("user_2").password(passwordEncoder().encode("1234567"))
.authorities("ROLE_USER").build());
return userDetailsService;
}
/**
* 设置加密方式
*
* @return PasswordEncoder
*/
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Security相关配置:
/**
* @author Mr.Zheng
* @Program: parent
* @Description: 添加Security权限配置
* @date 2020-05-03 13:59
*/
@Component
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 授权中心管理器
* @return AuthenticationManager
* @throws Exception 异常
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 拦截所有请求,使用httpBasic方式登陆
* @param http 请求
* @throws Exception 异常
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();
}
}
测试授权码模式:
使用该授权码获取accessToken:
测试密码模式获取accessToken:
三、受保护应用端案例代码
全局配置:
server:
port: 8081
logging:
level:
org.springframework.security: DEBUG
security:
oauth2:
resource:
####从认证授权中心上验证token
tokenInfoUri: http://localhost:8080/oauth/check_token
preferTokenInfo: true
client:
accessTokenUri: http://localhost:8080/oauth/token
userAuthorizationUri: http://localhost:8080/oauth/authorize
###appid
clientId: client_1
###appSecret
clientSecret: 123456
资源拦截配置:
/**
* @author Mr.Zheng
* @Program: parent
* @Description: 资源拦截配置
* @date 2020-05-03 15:43
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
// 对 api/order 请求进行拦截
http.authorizeRequests().antMatchers("/api/test/**").authenticated();
}
}
资源服务请求测试类:
/**
* @author Mr.Zheng
* @Program: parent
* @Description:
* @date 2020-05-03 15:44
*/
@RestController
@RequestMapping("/api/test")
public class TestController {
@RequestMapping("/add")
public String addOrder() {
return "add success!";
}
启动类开启Oauth2
/**
* @author Mr.Zheng
* @Program: parent
* @Description:
* @date 2020-05-03 15:42
*/
@SpringBootApplication
@EnableOAuth2Sso
public class TestOauth2Server {
public static void main(String[] args) {
SpringApplication.run(TestOauth2Server.class,args);
}
}
四、授权中心和受保护应用端联合测试
1)、没授权时:
2)、授权时:
先获取token
再用token访问资源
五、修改授权中心改成动态数据库查询的方式
下载官方数据库脚本:spring-security-oauth/schema.sql at main · spring-attic/spring-security-oauth · GitHub
新增数据库依赖:
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
spring:
datasource:
hikari:
connection-test-query: SELECT 1
minimum-idle: 1
maximum-pool-size: 5
pool-name: dbcp1
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/zhq_test_oauth?autoReconnect=true&useSSL=false
username: root
password: root
修改Oauth2配置:
/**
* @author Mr.Zheng
* @Program: parent
* @Description: 配置授权中心信息
* @date 2020-05-03 13:21
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;
/**
* accessToken有效期 两小时
*/
private int accessTokenValiditySeconds = 7200;
/**
* refreshToken有效期 两小时
*/
private int refreshTokenValiditySeconds = 7200;
@Bean
public TokenStore tokenStore() {
// return new InMemoryTokenStore(); //使用内存中的 token store
return new JdbcTokenStore(dataSource); /// 使用Jdbctoken store
}
/**
* 添加商户信息
*
* @param clients 商户
* @throws Exception 异常
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource)
//测试首次运行可以指定测试数据,如果数据库中没有则不报错,如果有或者第二次运行会报错,因为数据库已经存在了,需要注释掉
.withClient("client_1")
//商户secret
.secret(passwordEncoder().encode("123456"))
//回调地址
.redirectUris("https://www.baidu.com/")
/* OAuth2为我们提供了四种授权方式:
* 1、授权码模式(authorization code)用在客户端与服务端应用之间授权
* 2、简化模式(implicit)用在移动app或者web app(这些app是在用户的设备上的,如在手机上调起微信来进行认证授权)
* 3、密码模式(resource owner password credentials)应用直接都是受信任的(都是由一家公司开发的)
* 4、客户端模式(client credentials)用在应用API访问
*/
.authorizedGrantTypes("password", "client_credentials", "refresh_token", "authorization_code")
//授权范围
.scopes("all")
//accessToken有效期
.accessTokenValiditySeconds(accessTokenValiditySeconds)
//refreshToken有效期
.refreshTokenValiditySeconds(refreshTokenValiditySeconds);
}
/**
* 设置token类型
* @param endpoints
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager())
.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);
endpoints.authenticationManager(authenticationManager());
endpoints.userDetailsService(userDetailsService());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
// 允许表单认证
oauthServer.allowFormAuthenticationForClients();
// 允许check_token访问
oauthServer.checkTokenAccess("permitAll()");
}
@Bean
AuthenticationManager authenticationManager() {
AuthenticationManager authenticationManager = new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return daoAuhthenticationProvider().authenticate(authentication);
}
};
return authenticationManager;
}
@Bean
public AuthenticationProvider daoAuhthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService());
daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return daoAuthenticationProvider;
}
/**
* 设置添加用户信息,正常应该从数据库中读取
*
* @return UserDetailsService
*/
@Bean
UserDetailsService userDetailsService() {
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
userDetailsService.createUser(User.withUsername("user_1").password(passwordEncoder().encode("123456"))
.authorities("ROLE_USER").build());
userDetailsService.createUser(User.withUsername("user_2").password(passwordEncoder().encode("1234567"))
.authorities("ROLE_USER").build());
return userDetailsService;
}
/**
* 设置加密方式
*
* @return PasswordEncoder
*/
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
测试运行:
检查数据库发现测试商户已经导入到数据库了