Spring Boot Security Oauth2之客戶端模式及密碼模式實現


示例主要內容

  • 1.多認證模式(密碼模式、客戶端模式)
  • 2.token存到redis支持
  • 3.資源保護
  • 4.密碼模式用戶及權限存到數據庫
  • 5.使用說明

示例代碼-github

介紹

oauth2 client credentials 客戶端模式獲取access_token流程

客戶端模式(Client Credentials Grant)指客戶端以自己的名義,而不是以用戶的名義,向"服務提供商"進行認證。嚴格地說,客戶端模式並不屬於OAuth框架所要解決的問題。在這種模式中,用戶直接向客戶端注冊,客戶端以自己的名義要求"服務提供商"提供服務,其實不存在授權問題。

  • (A)客戶端向認證服務器進行身份認證,並要求一個訪問令牌。客戶端發出的HTTP請求,包含以下參數:
    granttype:表示授權類型,此處的值固定為"clientcredentials",必選項。
    scope:表示權限范圍,可選項。

  • (B)認證服務器確認無誤后,向客戶端提供訪問令牌。

oauth2 password 密碼模式獲取access_token流程

密碼模式(Resource Owner Password Credentials Grant)中,用戶向客戶端提供自己的用戶名和密碼。客戶端使用這些信息,向"服務商提供商"索要授權。
在這種模式中,用戶必須把自己的密碼給客戶端,但是客戶端不得儲存密碼。這通常用在用戶對客戶端高度信任的情況下,比如客戶端是操作系統的一部分,或者由一個著名公司出品。而認證服務器只有在其他授權模式無法執行的情況下,才能考慮使用這種模式。

  • (A)用戶向客戶端提供用戶名和密碼。

  • (B)客戶端將用戶名和密碼發給認證服務器,向后者請求令牌。 客戶端發出的HTTP請求,包含以下參數:
    grant_type:表示授權類型,此處的值固定為"password",必選項。
    username:表示用戶名,必選項。
    password:表示用戶的密碼,必選項。
    scope:表示權限范圍,可選項。

  • (C)認證服務器確認無誤后,向客戶端提供訪問令牌。

Oauth2提供的默認端點(endpoints)

  • /oauth/authorize:授權端點
  • /oauth/token:令牌端點
  • /oauth/confirm_access:用戶確認授權提交端點
  • /oauth/error:授權服務錯誤信息端點
  • /oauth/check_token:用於資源服務訪問的令牌解析端點
  • /oauth/token_key:提供公有密匙的端點,如果使用JWT令牌的話

示例使用介紹

1.端模式獲取access_token

http://localhost:8080/oauth/token?grant_type=client_credentials&scope=select&client_id=client_1&client_secret=123456

返回結果

{
    "access_token": "67a2c8f6-bd08-4409-a0d6-6ba61a4be950", "token_type": "bearer", "expires_in": 41203, "scope": "select" }

2.密碼模式獲取access_token

http://localhost:8080/oauth/token?username=user&password=123456&grant_type=password&scope=select&client_id=client_2&client_secret=123456

返回結果

{
    "access_token": "b3d2c131-1225-45b4-9ff5-51ec17511cee", "token_type": "bearer", "refresh_token": "8495d597-0560-4598-95ef-143c0855363c", "expires_in": 42417, "scope": "select" }

3.刷新access_token

http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=8495d597-0560-4598-95ef-143c0855363c&client_id=client_2&client_secret=123456

返回結果

{
    "access_token": "63de6c71-672f-418c-80eb-0c9abc95b67c", "token_type": "bearer", "refresh_token": "8495d597-0560-4598-95ef-143c0855363c", "expires_in": 43199, "scope": "select" }

4.訪問受保護的資源

http://localhost:8080/order/1?access_token=b3d2c131-1225-45b4-9ff5-51ec17511cee

正確返回數據

spring security oauth2代碼過程

security oauth2 整合的3個核心配置類

  • 1.資源服務配置 ResourceServerConfiguration
  • 2.授權認證服務配置 AuthorizationServerConfiguration
  • 3.security 配置 SecurityConfiguration

1.pom.xml添加maven依賴

    <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.3.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.1</version> <scope>test</scope> </dependency> </dependencies>

主要使用了:security、oauth2、redis、mysql、mybatis-plus等組件

2.認證授權配置AuthorizationServerConfigurerAdapter.java

@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { private static final String RESOURCE_IDS = "order"; @Autowired AuthenticationManager authenticationManager; @Autowired RedisConnectionFactory redisConnectionFactory; @Autowired private UserDetailsService userDetailsService; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { String finalSecret = "{bcrypt}" + new BCryptPasswordEncoder().encode("123456"); //配置兩個客戶端,一個用於password認證一個用於client認證 clients.inMemory() //client模式 .withClient("client_1") .resourceIds(RESOURCE_IDS) .authorizedGrantTypes("client_credentials", "refresh_token") .scopes("select") .authorities("oauth2") .secret(finalSecret) .and() //密碼模式 .withClient("client_2") .resourceIds(RESOURCE_IDS) .authorizedGrantTypes("password", "refresh_token") .scopes("select") .authorities("oauth2") .secret(finalSecret); } /** * 認證服務端點配置 */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints //用戶管理 .userDetailsService(userDetailsService) //token存到redis .tokenStore(new RedisTokenStore(redisConnectionFactory)) //啟用oauth2管理 .authenticationManager(authenticationManager) //接收GET和POST .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) { oauthServer.allowFormAuthenticationForClients(); } }

3.資源配置ResourceServerConfig.java

@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { private static final String RESOURCE_IDS = "order"; @Override public void configure(ResourceServerSecurityConfigurer resources) { resources.resourceId(RESOURCE_IDS).stateless(true); } @Override public void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity .authorizeRequests() .antMatchers("/order/**").authenticated(); //配置order訪問控制,必須認證過后才可以訪問 } }

4.密碼模式的用戶及權限存到了數據庫,UserDetailsServiceImpl.java


@Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserServiceImpl userService; /** * 實現UserDetailsService中的loadUserByUsername方法,用於加載用戶數據 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.queryUserByUsername(username); if (user == null) { throw new UsernameNotFoundException("用戶不存在"); } //用戶權限列表 Collection<? extends GrantedAuthority> authorities = userService.queryUserAuthorities(user.getId()); return new AuthUser( user.getId(), user.getUsername(), user.getPassword(), true, true, true, true, authorities); } } 

5.WebSecurityConfig配置

@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } /** * 注入AuthenticationManager接口,啟用OAuth2密碼模式 * * @return * @throws Exception */ @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { AuthenticationManager manager = super.authenticationManagerBean(); return manager; } /** * 通過HttpSecurity實現Security的自定義過濾配置 * * @param httpSecurity * @throws Exception */ @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity .requestMatchers().anyRequest() .and() .authorizeRequests() .antMatchers("/oauth/**").permitAll(); } }

6.application.yml配置

server:  port: 8080 spring:  thymeleaf:  encoding: UTF-8  cache: false  datasource:  driver-class-name: com.mysql.cj.jdbc.Driver  url: jdbc:mysql://localhost:3306/easy_web?useSSL=false&serverTimezone=UTC  username: root  password: 123456  redis:  host: 127.0.0.1  port: 6379  password: logging.level.org.springframework.security: DEBUG

7.inital.sql數據庫初始化腳本

DROP TABLE IF EXISTS `user`; DROP TABLE IF EXISTS `role`; DROP TABLE IF EXISTS `user_role`; DROP TABLE IF EXISTS `role_permission`; DROP TABLE IF EXISTS `permission`; CREATE TABLE `user` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `role` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `user_role` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `user_id` bigint(11) NOT NULL, `role_id` bigint(11) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `role_permission` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `role_id` bigint(11) NOT NULL, `permission_id` bigint(11) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `permission` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `url` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `description` varchar(255) NULL, `pid` bigint(11) NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO user (id, username, password) VALUES (1,'user','{bcrypt}$2a$10$Tme77eHtXzcB8ghQUepYguJr7P7ESg0Y7XHMnk60s.kf2A.BWBD9m'); INSERT INTO user (id, username , password) VALUES (2,'admin','{bcrypt}$2a$10$Tme77eHtXzcB8ghQUepYguJr7P7ESg0Y7XHMnk60s.kf2A.BWBD9m'); INSERT INTO role (id, name) VALUES (1,'USER'); INSERT INTO role (id, name) VALUES (2,'ADMIN'); INSERT INTO permission (id, url, name, pid) VALUES (1,'/user/common','common',0); INSERT INTO permission (id, url, name, pid) VALUES (2,'/user/admin','admin',0); INSERT INTO user_role (user_id, role_id) VALUES (1, 1); INSERT INTO user_role (user_id, role_id) VALUES (2, 1); INSERT INTO user_role (user_id, role_id) VALUES (2, 2); INSERT INTO role_permission (role_id, permission_id) VALUES (1, 1); INSERT INTO role_permission (role_id, permission_id) VALUES (2, 1); INSERT INTO role_permission (role_id, permission_id) VALUES (2, 2);

經過以上七個步驟,我們快速實現了Oauth2的密碼模式和客戶模式功能。

資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM