溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Spring Security OAuth2怎么獲取token

發(fā)布時(shí)間:2021-11-17 09:43:03 來(lái)源:億速云 閱讀:698 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“Spring Security OAuth2怎么獲取token”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

一、項(xiàng)目知識(shí)準(zhǔn)備

  1. 什么是OAuth3

    OAuth 2.0 的標(biāo)準(zhǔn)是 RFC 6749 文件 OAuth 引入了一個(gè)授權(quán)層,用來(lái)分離兩種不同的角色:客戶(hù)端和資源所有者。......資源所有者同意以后,資源服務(wù)器可以向客戶(hù)端頒發(fā)令牌??蛻?hù)端通過(guò)令牌,去請(qǐng)求數(shù)據(jù):

    Spring Security OAuth2怎么獲取token

  2. OAuth3核心-授權(quán)

    Spring Security OAuth2怎么獲取token

  3. OAuth3的四種方式

模式
授權(quán)碼(authorization-code)
隱藏式(implicit)
密碼式(password)
客戶(hù)端憑證(client credentials)

4. 握手流程(摘自RFC6749)

Spring Security OAuth2怎么獲取token

5. SpringSecurity

基于Spring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪(fǎng)問(wèn)控制解決方式的安全框架(簡(jiǎn)單說(shuō)是對(duì)訪(fǎng)問(wèn)權(quán)限進(jìn)行控制嘛),應(yīng)用的安全性包括用戶(hù)認(rèn)證(Authentication)和用戶(hù)授權(quán)(Authorization)兩個(gè)部分

*6. SpringSecurity 中默認(rèn)的內(nèi)置過(guò)濾列表:

Spring Security OAuth2怎么獲取token

(其他后續(xù)補(bǔ)充)

二、項(xiàng)目準(zhǔn)備

1. 環(huán)境

 SpringBoot 2.1.0.RELEASE jdk1.8   SpringCloud Greenwich.SR1  consul服務(wù)發(fā)現(xiàn)與注冊(cè)
  1. 項(xiàng)目

項(xiàng)目描述
fp-commonsjar公用
fp-gateway網(wǎng)關(guān)
fp-authorization-serverOAuth3認(rèn)證服務(wù)器
3. 項(xiàng)目搭建
(1)網(wǎng)關(guān)搭建 frame-gateway

    pom.xml:
        引入依賴(lài)文件;在啟動(dòng)器上添加 注冊(cè)監(jiān)聽(tīng)@EnableDiscoveryClient 
        并注入 DiscoveryClientRouteDefinitionLocator 
    application.xml: 
        spring-main-allow-bean-definition-overriding: true (相同名稱(chēng)注入允許覆蓋)
        spring.application.name:SpringCloud-consul-gateway   (設(shè)置應(yīng)用名稱(chēng)必須)
        bootstrap.yml 中配置 consul(比application先加載) 
        prefer-ip-address: true (使用ip注冊(cè),有些網(wǎng)絡(luò)會(huì)出現(xiàn)用主機(jī)名來(lái)獲取注冊(cè)的問(wèn)題)

(2)fp-commons jar公用

    pom.xml:
          引入依賴(lài)文件;添加一些公用方法

(3)fp-authorization-server

(git中提交了一個(gè)至簡(jiǎn)版本的OAuth3認(rèn)證中心,只有token生成功能,沒(méi)有資源保護(hù)以及認(rèn)證)

    只需要配置AuthorizationServerConfigurerAdapter 認(rèn)證服務(wù)器
    以及WebSecurityConfigurerAdapter SpringSecurity配置 兩個(gè)文件,就能實(shí)現(xiàn)token生成。
    如果沒(méi)有需要保護(hù)的資源不用ResourceServerConfigurerAdapter 資源服務(wù)器配置

三、認(rèn)證服務(wù)器搭建

基本的SpringBoot搭建略過(guò),這里只介紹SpringSecurity OAuth3的token實(shí)現(xiàn),基本的數(shù)據(jù)處理以及其他看源碼。

首先完成ClientDetailsService的自定義實(shí)現(xiàn)(獲取客戶(hù)端相關(guān)信息)

/**
* @Description 自定義客戶(hù)端數(shù)據(jù)
* @Author wwz
* @Date 2019/07/28
* @Param
* @Return
*/
@Service
public class MyClientDetailsService implements ClientDetailsService {
    @Autowired
    private AuthClientDetailsMapper authClientDetailsMapper;
    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        AuthClientDetails clientDetails = authClientDetailsMapper.selectClientDetailsByClientId(clientId);
        if (clientDetails == null) {
            throw new ClientRegistrationException("該客戶(hù)端不存在");
        }
        MyClientDetails details = new MyClientDetails(clientDetails);
        return details;
    }
}

以及UserDetailsService的自定義實(shí)現(xiàn)(獲取用戶(hù)相關(guān)信息)

/**
 * @Description 自定義用戶(hù)驗(yàn)證數(shù)據(jù)
 * @Author wwz
 * @Date 2019/07/28
 * @Param
 * @Return
 */
@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private AuthUserMapper authUserMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 自定義用戶(hù)權(quán)限數(shù)據(jù)
        AuthUser authUser = authUserMapper.selectByUsername(username);
        if (authUser == null) {
            throw new UsernameNotFoundException("用戶(hù)名不存在");
        }
        if (!authUser.getValid()) {
            throw new UsernameNotFoundException("用戶(hù)不可用");
        }
        Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
        if (authUser.getAuthRoles() != null) {
            for (AuthRole role : authUser.getAuthRoles()) {
                // 當(dāng)前角色可用
                if (role.getValid()) {
                    //角色必須是ROLE_開(kāi)頭
                    GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleName());
                    grantedAuthorities.add(grantedAuthority);
                    if (role.getAuthPermissions() != null) {
                        for (AuthPermission permission : role.getAuthPermissions()) {
                            // 當(dāng)前權(quán)限可用
                            if (permission.getValid()) {
                                // 擁有權(quán)限設(shè)置為   auth/member/GET  可以訪(fǎng)問(wèn)auth服務(wù)下面 member的查詢(xún)方法
                                GrantedAuthority authority = new SimpleGrantedAuthority(permission.getServicePrefix() + "/" + permission.getUri() + "/" + permission.getMethod());
                                grantedAuthorities.add(authority);
                            }
                        }
                    }
                }
                //獲取權(quán)限
            }
        }
        MyUserDetails userDetails = new MyUserDetails(authUser, grantedAuthorities);
        return userDetails;
    }
}

然后新建認(rèn)證服務(wù)配置MySecurityOAuth3Config,繼承AuthorizationServerConfigurerAdapter

/**
 * @Description OAuth3認(rèn)證服務(wù)配置
 * @Author wwz
 * @Date 2019/07/28
 * @Param
 * @Return
 */
@Configuration
@EnableAuthorizationServer
public class MySecurityOAuth3Config extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;    // 認(rèn)證方法入口

    @Autowired
    private RedisConnectionFactory connectionFactory;  // redis連接工廠(chǎng)

    @Autowired
    private MyUserDetailsService userDetailsService;  // 自定義用戶(hù)驗(yàn)證數(shù)據(jù)

    @Autowired
    private MyClientDetailsService clientDetailsService; // 自定義客戶(hù)端數(shù)據(jù)
    // 加密方式
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /***
     * 設(shè)置token用redis保存
     */
    @Bean
    public TokenStore tokenStore() {
        //token保存在redis中(也可以保存在數(shù)據(jù)庫(kù)、內(nèi)存中new InMemoryTokenStore()、或者jwt;)。
        //如果保存在中間件(數(shù)據(jù)庫(kù)、Redis),那么資源服務(wù)器與認(rèn)證服務(wù)器可以不在同一個(gè)工程中。
        //注意:如果不保存access_token,則沒(méi)法通過(guò)access_token取得用戶(hù)信息
        RedisTokenStore redis = new RedisTokenStore(connectionFactory);
        return redis;
    }

    /**
     * 配置令牌端點(diǎn)(Token Endpoint)的安全約束
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients();   // 允許表單登錄
    }

    /**
     * 配置 oauth_client_details【client_id和client_secret等】信息的認(rèn)證【檢查ClientDetails的合法性】服務(wù)
     * 設(shè)置 認(rèn)證信息的來(lái)源:數(shù)據(jù)庫(kù),內(nèi)存,也可以自己實(shí)現(xiàn)ClientDetailsService的loadClientByClientId 方法自定義數(shù)據(jù)源
     * 自動(dòng)注入:ClientDetailsService的實(shí)現(xiàn)類(lèi) JdbcClientDetailsService (檢查 ClientDetails 對(duì)象)
     * 這個(gè)方法主要是用于校驗(yàn)注冊(cè)的第三方客戶(hù)端的信息,可以存儲(chǔ)在數(shù)據(jù)庫(kù)中,默認(rèn)方式是存儲(chǔ)在內(nèi)存中
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 設(shè)置從自定義接口獲取客戶(hù)端信息
        clients.withClientDetails(clientDetailsService);
// clients.inMemory() // 使用in-memory存儲(chǔ)
//                .withClient("client_name") // client_id
//                .secret(passwordEncoder().encode("111")) // client_secret
//                .redirectUris("http://localhost:8001")
//                // 該client允許的授權(quán)類(lèi)型
//                .authorizedGrantTypes("password", "authorization_code", "refresh_token", "client_credentials")
//                .scopes("app", "app1", "app3"); // 允許的授權(quán)范圍
    }

    /**
     * 配置授權(quán)(authorization)以及令牌(token)的訪(fǎng)問(wèn)端點(diǎn)和令牌服務(wù)(token services)
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .tokenStore(tokenStore())  // 配置token存儲(chǔ)
                .userDetailsService(userDetailsService)  // 配置自定義的用戶(hù)權(quán)限數(shù)據(jù),不配置會(huì)導(dǎo)致token無(wú)法刷新
                .authenticationManager(authenticationManager)
                .tokenServices(defaultTokenServices());      // 加載token配置

    }

    /**
     * 把認(rèn)證的token保存到redis
     * <p>注意,自定義TokenServices的時(shí)候,需要設(shè)置@Primary,否則報(bào)錯(cuò),</p>
     * 自定義的token
     * 認(rèn)證的token是存到redis里的 若ClientDetails中設(shè)定了有效時(shí)間則以設(shè)定值為準(zhǔn)
     */
    @Primary
    @Bean
    public DefaultTokenServices defaultTokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(clientDetailsService);
        tokenServices.setAccessTokenValiditySeconds(60 * 60 * 12);  // token有效期自定義設(shè)置,默認(rèn)12小時(shí)
        tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);  // refresh_token默認(rèn)30天
        return tokenServices;
    }
}

接著新建Security的配置MySecurityConfig 繼承WebSecurityConfigurerAdapter

**
 * @Description security 配置
 * ResourceServerConfigurerAdapter 是比WebSecurityConfigurerAdapter 的優(yōu)先級(jí)低的
 * @Author wwz
 * @Date 2019/07/28
 * @Param
 * @Return
 */
@Configuration
@EnableWebSecurity
@Order(2)  // WebSecurityConfigurerAdapter 默認(rèn)為100 這里配置為2設(shè)置比資源認(rèn)證器高
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    // 自定義用戶(hù)驗(yàn)證數(shù)據(jù)
    @Bean
    public MyUserDetailsService userDetailsService() {
        return new MyUserDetailsService();
    }

    // 加密方式
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 驗(yàn)證器加載
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 匹配oauth相關(guān),匹配健康,匹配默認(rèn)登錄登出 在httpSecurity處理,,其他到ResourceServerConfigurerAdapter OAuth3處理  1
                .requestMatchers().antMatchers("/oauth/**", "/actuator/health", "/login", "/logout")
                .and()
                // 匹配的全部無(wú)條件通過(guò) permitAll 2
                .authorizeRequests().antMatchers("/oauth/**", "/actuator/health", "/login", "/logout").permitAll()
                // 匹配條件1的 并且不再條件2通過(guò)范圍內(nèi)的其他url全部需要驗(yàn)證登錄
                .and().authorizeRequests().anyRequest().authenticated()
                // 啟用登錄驗(yàn)證
                .and().formLogin().permitAll();
        // 不啟用 跨站請(qǐng)求偽造 默認(rèn)為啟用, 需要啟用的話(huà)得在form表單中生成一個(gè)_csrf
        http.csrf().disable();
    }

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

到此,SpringSecurity OAuth3至簡(jiǎn)的項(xiàng)目搭建完成,下一步為4種token的基本驗(yàn)證

四、4種token獲?。ㄟ@里使用postman做token獲?。?/h3>
  1. password模式認(rèn)證

請(qǐng)求地址:

http://192.168.3.14:8001/auth/oauth/token?grant_type=password&username=username&password=111

參數(shù):

參數(shù)名說(shuō)明
grant_type類(lèi)型必須為password
username用戶(hù)名
password密碼
client_id客戶(hù)端id
client_serce客戶(hù)端密碼
請(qǐng)求:

Spring Security OAuth2怎么獲取token Spring Security OAuth2怎么獲取token

響應(yīng): 返回信息 包括 access_token 通行token, refresh_token 重新申請(qǐng)token,scope資源范圍 Spring Security OAuth2怎么獲取token

驗(yàn)證:

無(wú)權(quán)訪(fǎng)問(wèn)頁(yè)面

Spring Security OAuth2怎么獲取token

訪(fǎng)問(wèn)頁(yè)面

Spring Security OAuth2怎么獲取token

  1. client_credentials模式

請(qǐng)求地址:

http://192.168.3.14:8001/auth/oauth/token?grant_type=client_credentials&client_id=client_name&client_secret=111

參數(shù):

參數(shù)名說(shuō)明
grant_type類(lèi)型必須為client_credentials
client_id客戶(hù)端id
client_serce客戶(hù)端密碼
請(qǐng)求

Spring Security OAuth2怎么獲取token

響應(yīng):返回參數(shù) 包括access_token,scope 權(quán)限范圍 (但是不包含refresh_token) Spring Security OAuth2怎么獲取token

驗(yàn)證:默認(rèn)無(wú)任何權(quán)限 當(dāng)然,這里的權(quán)限也可以在ClientDetails中的authorities字段中默認(rèn)增加權(quán)限

Spring Security OAuth2怎么獲取token Spring Security OAuth2怎么獲取token

  1. refresh_token 模式

    refresh_token 只有請(qǐng)求過(guò)一次并且獲取到refresh_token才能用該值重新申請(qǐng)可用token,并且,申請(qǐng)了新的token后,原先為過(guò)期的token立即失效,refresh_token作為新的token的refresh_token繼續(xù)使用。

請(qǐng)求地址:

http://192.168.3.14:8001/auth/oauth/token?grant_type=refresh_token&refresh_token=384b02e7-66d5-4d5b-8179-53793f7ba40b

參數(shù)

參數(shù)名說(shuō)明
grant_type類(lèi)型必須為refresh_token
refresh_token刷新token

請(qǐng)求:

Spring Security OAuth2怎么獲取token

響應(yīng):返回結(jié)果包括 新的token,原refresh_token,scope權(quán)限 Spring Security OAuth2怎么獲取token

  1. authorization_code模式

請(qǐng)求:

第一次請(qǐng)求:http://192.168.3.14:8001/auth/oauth/authorize?response_type=code&client_id=client_name&redirect_uri=http://192.168.3.14:8001/auth/oauth/token&scope=auth
第二次請(qǐng)求:http://192.168.3.14:8001/auth/oauth/token?grant_type=authorization_code&redirect_uri=http://192.168.3.14:8001/auth/oauth/token&code=mbeBvY

參數(shù):

第一次參數(shù)

參數(shù)名說(shuō)明
response_type類(lèi)型必須為code
client_id客戶(hù)端id
redirect_uri返回code地址 與后端client_Id對(duì)應(yīng) redirect_uri,與第二步請(qǐng)求token對(duì)應(yīng)

第二次參數(shù)

參數(shù)名說(shuō)明
grant_type類(lèi)型必須為authorization_code
code為返回code 這里為 mbeBvY
redirect_uri返回code地址 上一步redirect_uri http://192.168.3.14:8001/auth/oauth/token

上述,填錯(cuò)一個(gè)就會(huì)報(bào)錯(cuò)code只能使用一次 再次請(qǐng)求失效

第一次請(qǐng)求后跳轉(zhuǎn) 登錄界面

Spring Security OAuth2怎么獲取token

登錄后跳轉(zhuǎn)授權(quán)頁(yè)面然后返回到攜帶的redirect_uri路徑 并帶上code

Spring Security OAuth2怎么獲取token

第二次請(qǐng)求

Spring Security OAuth2怎么獲取token

響應(yīng):返回結(jié)果包括 token, refresh_token,scope權(quán)限

Spring Security OAuth2怎么獲取token

“Spring Security OAuth2怎么獲取token”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI