使用SpringSecurityOAuth2配置自定義Token實現OAuth2授權示例


  本文記錄一下使用SpringSecurityOAuth2配置自定義Token實現OAuth2授權的步驟

  1、相關知識

  OAuth協議簡介:https://www.cnblogs.com/javasl/p/13054133.html

  OAuth 2.0官網:https://oauth.net/2/

  使用SpringSecurityOAuth2默認實現OAuth2授權示例:https://www.cnblogs.com/javasl/p/13060284.html

  2、構建項目

  本文使用的springboot版本是2.0.4.RELEASE,不同版本可能會有所區別。下面是主要的配置文件和類:

  1)pom依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

  2)application.properties

#不需要,暫時寫死在代碼中,重構時移植到此處即可

  3)主配置類

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic().and().csrf().disable();
    }
    @Bean("authenticationManager")
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

  4)用戶認證類

@Component
public class MyUserDetailsService implements UserDetailsService{ @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("登錄用戶名:"+username); String password = passwordEncoder.encode("123456"); return new User(username,password,true,true,true,true, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER")); } }

  5)認證服務類

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                 .authenticationManager(authenticationManager)
                 .userDetailsService(userDetailsService);
    }
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
               .inMemory()//Token保存在內存中
               .withClient("MyProject").secret(passwordEncoder.encode("MyProject_123"))//指明client-id和client-secret
               .accessTokenValiditySeconds(7200)//令牌有效時間,單位秒
               .authorizedGrantTypes("refresh_token","password","authorization_code")//支持刷新令牌、密碼模式、授權碼模式
               .scopes("all","read","write")//權限有哪些,如果這兩配置了該參數,客戶端發請求可以不帶參數,使用配置的參數
               .redirectUris("http://127.0.0.1:8080/login");
    }
}

  說明:

  a)client-secret必須加密,否則在后面測試中,總是彈出讓輸入用戶名、密碼。

  b)代碼中配置了權限,客戶端可以不攜帶scopes參數,如果攜帶必須是all、read、write或者其組合。

  c)使用授權碼模式,必須配置redirectUris,使用密碼模式可以不配置,去掉該語句即可。

  6)啟動類

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

  3、測試驗證

  1)驗證默認scope情況獲取Token

  

  

  2)驗證指定scope情況獲取Token

  

  說明:

  a)發送參數是all write,返回scope是all write

  b)發送參數是write read,返回scope是read write

  c)發送除了all read write以外的任何scope值,都返回"Invalid scope",不能用逗號分隔。

  3)驗證授權碼模式

  a)瀏覽器輸入:http://localhost:8080/oauth/authorize?response_type=code&client_id=MyProject&scope=all

  

  b)輸入用戶名任意,密碼123456

  

  c)點擊Authorize,瀏覽器跳轉如下地址,授權碼為GPLd04

  

  d)獲取Token

  

  

  4、給多個應用發送Token

  修改認證服務類中configure方法,如下,模擬給兩個應用發送令牌:

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
InMemoryClientDetailsServiceBuilder builder
= clients.inMemory(); List<String> list = new ArrayList<String>(); String app1 = "MyProject,MyProject_123,7200"; String app2 = "Test,Test123,10"; list.add(app1); list.add(app2);
String client
= ""; String secret = ""; int accessTokenValiditySeconds; for(String str:list) { client = str.split(",")[0]; secret = str.split(",")[1]; accessTokenValiditySeconds = Integer.valueOf(str.split(",")[2]); builder.withClient(client).secret(passwordEncoder.encode(secret))      .accessTokenValiditySeconds(accessTokenValiditySeconds)
.refreshTokenValiditySeconds(2592000)      .authorizedGrantTypes("refresh_token","password")      .scopes("all","read","write"); } }

  5、使用Redis存儲Token

  使用Redis存儲Token,當應用重啟后,Token不會改變。

  1)引入Redis依賴,並添加配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring.redis.host = 192.168.7.151
spring.redis.port = 637

  2)配置TokenStore為Redis

@Configuration
public class TokenStoreConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;
    
    @Bean
    public TokenStore redisTokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }
}

  3)修改認證服務類中configure方法,給endpoints指定Token存儲方式為Redis

@Autowired
private TokenStore tokenStore;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
             .tokenStore(tokenStore)
             .authenticationManager(authenticationManager)
             .userDetailsService(userDetailsService);
}

  4)演示,初始時候Redis的key為空,當Rest插件請求一次Token后,Redis中寫入了數據。重啟應用再訪問,Token不改變。

  

 

 

 

 

 

  

 


免責聲明!

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



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