SpringSecurity+Oauth2+JWT安全框架(一)


一、添加依賴

在這里我們也需要導入redis的相關依賴,因為實際使用過程,需要人為干預令牌的有效時間

<!--Oauth2依賴-->
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>${security-oauth2-version}</version>
</dependency>
<!--使用jwt令牌-->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-jwt</artifactId>
    <version>${jwt-version}</version>
</dependency>
<!-- 配置使用redis啟動器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>${redis-jedis-version}</version>
</dependency>

<!--fastjson轉換-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>${alibaba-fastjon-version}</version>
</dependency>

 

二、生成jks證書

在導入依賴包后, 我們需要再redsources文件下創建配置文件application.yml,在這里我們不做過多的說明,我們要使用到JWT安全證書,並通過證書生成令牌,並將生成的證書文件xxx.jks放到resources文件下。

 

三、創建SecurityConfiguration.java實體類,並讓其繼承WebSecurityConfigurerAdapt,其中myUserDetailsServiceImpl是進行驗證登陸者賬號和密碼的實體類

@Configuration
@EnableWebSecurity
class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource(name = "myUserDetailsServiceImpl")
    private UserDetailsService userDetailsService;


    @Override
    public void configure(WebSecurity web) throws Exception {
        //用戶登錄認證、用戶退出、用戶獲取jwt令牌
        web.ignoring().antMatchers("/XXX");
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        AuthenticationManager manager = super.authenticationManagerBean();
        return manager;
    }

    @Override
    protected UserDetailsService userDetailsService() {
        return userDetailsService;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    //采用bcrypt對密碼進行編碼
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
//        http.csrf().disable()
//                .httpBasic().and()
//                .formLogin()
//                .and()
//                .authorizeRequests().anyRequest().authenticated();
        http.authorizeRequests().anyRequest().permitAll().and().csrf().disable();

    }

}

 

四、UserDetailsServiceImpl實體類,我們可以看到這里做了賬號密碼驗證並且使用了加密

 

五、創建實體類AuthServerConfig.java實體類,該實體類做了關於oauth2客戶端的一些配置

@Configuration
@EnableAuthorizationServer
public class CustomAuthServerConfig extends AuthorizationServerConfigurerAdapter {

    /*jwt令牌轉換器*/
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    /*在這里userDetailService一定要加上@Autowired,否則會報錯找不到服務器UserDetailsService is required*/
    @Resource(name = "myUserDetailsServiceImpl")
    UserDetailsService userDetailsService;
    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    TokenStore tokenStore;
    @Autowired
    PasswordEncoder passwordEncoder;
    @Autowired
    private SecurityAuth securityAuth;

    /* 授權服務器的安全配置*/
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
                .tokenKeyAccess("permitAll()")
                .allowFormAuthenticationForClients()
                /*校驗token需要認證通過,可采用http basic認證*/
                .checkTokenAccess("isAuthenticated()");
    }

    /*設置認證請求相關參數,例如客戶端賬號和密碼、令牌有效時間等等*/
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient(securityAuth.getClientId())/*客戶端id*/
                .secret(passwordEncoder.encode(securityAuth.getClientSecret()))/*密碼,要保密*/
                .accessTokenValiditySeconds(60 * 60 * X)/*訪問令牌有效期X個小時*/
.refreshTokenValiditySeconds(60 * 60 * X)/*刷新令牌有效期X個小時*/
/*授權客戶端請求認證服務的類型authorization_code:根據授權碼生成令牌, client_credentials:客戶端認證,refresh_token:刷新令牌,password:密碼方式認證*/ .authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token", "password") .redirectUris("http://localhost") .scopes("app");/*客戶端范圍,名稱自定義,必填*/ } @Bean public TokenEnhancer customTokenEnhancer() { return new CustomTokenEnhancer(); } /*授權服務器端點配置*/ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { /*endpoints.authenticationManager(authenticationManager)認證管理器 .userDetailsService(userDetailsService);/*用戶信息service*/ /*將增強的token設置到增強鏈中*/ TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); enhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer(), jwtAccessTokenConverter())); endpoints.accessTokenConverter(jwtAccessTokenConverter) .authenticationManager(authenticationManager)/*認證管理器*/ .tokenStore(tokenStore)/*令牌存儲*/ .userDetailsService(userDetailsService)/*用戶信息service*/ .tokenEnhancer(enhancerChain);//自定義jwt令牌中的攜帶參數 } //使用證書文件生成jwt令牌的 @Bean @Autowired public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) { return new JwtTokenStore(jwtAccessTokenConverter); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { /* 證書文件*/ String key_location = "XXXX.jks";
/*密鑰庫密碼*/ String keystore_password = "XXXX";
/*訪問證書路徑*/ ClassPathResource resource = new ClassPathResource(key_location); /*密鑰工廠*/ KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, keystore_password.toCharArray()); /*密鑰別名*/ String alias = "XXXX";
/*密鑰庫密碼*/ String keypassword = "XXXX"; KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias, keypassword.toCharArray()); JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setKeyPair(keyPair); return converter; } }

 這樣認證服務器的配置參數就完成了,啟動服務后,我們就可以測試發送驗證請求,因為在這里我們僅僅敘述的是功能的實現,賬號密碼都用一些最簡單的,這塊的業務邏輯,可以根據實際情況去編寫,是否能獲取到返回的令牌

 

六、測試

密碼模式測試

Post請求:http://localhost:8080/oauth/token

參數:

grant_type:密碼模式授權填寫password

username:賬號

password:密碼

此鏈接需要使用http Basic認證,這點需要注意以下,http Basic中認證信息的username和password就寫我們之前在代碼中預先寫好的內容

access_token:訪問令牌,攜帶此令牌訪問資源

token_type:在請求資源的時候,在令牌之前加上該信息,並且空一格

refresh_token:刷新令牌,使用此令牌可以延長訪問令牌的過期時間

expires_in:過期時間,單位為秒

scope:范圍,與定義的客戶端范圍一致

 

看到以上信息的時候,恭喜你測試成功!


免責聲明!

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



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