<!-- 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 异常*/@Overridepublic 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*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager()).allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);endpoints.authenticationManager(authenticationManager());endpoints.userDetailsService(userDetailsService());}@Overridepublic void configure(AuthorizationServerSecurityConfigurer oauthServer) {// 允许表单认证oauthServer.allowFormAuthenticationForClients();// 允许check_token访问oauthServer.checkTokenAccess("permitAll()");}@BeanAuthenticationManager authenticationManager() {AuthenticationManager authenticationManager = new AuthenticationManager() {@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {return daoAuhthenticationProvider().authenticate(authentication);}};return authenticationManager;}@Beanpublic AuthenticationProvider daoAuhthenticationProvider() {DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService(userDetailsService());daoAuthenticationProvider.setHideUserNotFoundExceptions(false);daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());return daoAuthenticationProvider;}/*** 设置添加用户信息,正常应该从数据库中读取** @return UserDetailsService*/@BeanUserDetailsService 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*/@BeanPasswordEncoder 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@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}/*** 拦截所有请求,使用httpBasic方式登陆* @param http 请求* @throws Exception 异常*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();}}
测试授权码模式:
访问http://localhost:8080/oauth/authorize?response_type=code&client_id=client_1&redirect_uri=https://www.baidu.com/
使用该授权码获取accessToken:
访问http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=client_1&client_secret=123456&code=EwaTib&redirect_uri=https://www.baidu.com/&scope=all
测试密码模式获取accessToken:
三、受保护应用端案例代码
全局配置:
server:port: 8081logging:level:org.springframework.security: DEBUGsecurity:oauth2:resource:####从认证授权中心上验证tokentokenInfoUri: http://localhost:8080/oauth/check_tokenpreferTokenInfo: trueclient:accessTokenUri: http://localhost:8080/oauth/tokenuserAuthorizationUri: http://localhost:8080/oauth/authorize###appidclientId: client_1###appSecretclientSecret: 123456
资源拦截配置:
/*** @author Mr.Zheng* @Program: parent* @Description: 资源拦截配置* @date 2020-05-03 15:43*/
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {@Overridepublic 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 1minimum-idle: 1maximum-pool-size: 5pool-name: dbcp1driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/zhq_test_oauth?autoReconnect=true&useSSL=falseusername: rootpassword: 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;@Beanpublic TokenStore tokenStore() {// return new InMemoryTokenStore(); //使用内存中的 token storereturn new JdbcTokenStore(dataSource); /// 使用Jdbctoken store}/*** 添加商户信息** @param clients 商户* @throws Exception 异常*/@Overridepublic 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*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager()).allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);endpoints.authenticationManager(authenticationManager());endpoints.userDetailsService(userDetailsService());}@Overridepublic void configure(AuthorizationServerSecurityConfigurer oauthServer) {// 允许表单认证oauthServer.allowFormAuthenticationForClients();// 允许check_token访问oauthServer.checkTokenAccess("permitAll()");}@BeanAuthenticationManager authenticationManager() {AuthenticationManager authenticationManager = new AuthenticationManager() {@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {return daoAuhthenticationProvider().authenticate(authentication);}};return authenticationManager;}@Beanpublic AuthenticationProvider daoAuhthenticationProvider() {DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService(userDetailsService());daoAuthenticationProvider.setHideUserNotFoundExceptions(false);daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());return daoAuthenticationProvider;}/*** 设置添加用户信息,正常应该从数据库中读取** @return UserDetailsService*/@BeanUserDetailsService 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*/@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
测试运行:
检查数据库发现测试商户已经导入到数据库了