Spring Cloud微服務安全實戰_4-6_OAuth2的Scope參數_token轉換為用戶信息


一、通過OAuth2 Toke的Scope參數控制權限

1,在服務端認證服務器里,通過配置客戶端的Scope,可以控制給這個客戶端生成的token有哪些權限

 

 

 2,在客戶端,申請令牌的時候,可以指定scope

示例:在資源服務器 (nb-order-api)里,控制post請求的token ,其scope必須包含write權限,get請求的token必須包含read權限。

 

 

用postman客戶端(clientId=orderApp)去認證服務器申請一個scpoe=read的token,去調用資源服務器里的Post請求:

 

 

 調用這個創建訂單的Post請求:

 

 返回錯誤信息:

 二,將token轉換為用戶信息

目前在資源服務器里,想要獲取用戶信息,在Controller里,可以通過 @AuthenticationPrincipal 注解,獲取生成token的用戶名。但是獲取不到用戶的其他信息,如userId等。

做如下修改:

1,在資源服務器的安全配置: OAuth2WebSecurityConfig 里,的  tokenServices方法里,配置一個 AccessTokenConverter,用來將token信息轉換為 User 信息

2,新建UserDetailsService的實現類

OAuth2WebSecurityConfig:
package com.nb.security.resource.server;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
import org.springframework.security.oauth2.provider.token.*;

/**
 * 怎么驗發往本服務的請求頭的令牌
 * 1,自定義tokenServices ,說明去哪里去驗token
 * 2,重寫authenticationManagerBean()方法,將AuthenticationManager暴露為一個Bean
 *    要認證跟用戶相關的信息,一般用 AuthenticationManager
 *
 * 這樣配置了后,所有發往nb-order-api的請求,
 * 需要驗token的時候就會發請求去http://localhost:9090/oauth/check_token驗token,獲取到token對應的用戶信息
 */
@Configuration
@EnableWebSecurity
public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 通過這個Bean,去遠程調用認證服務器,驗token
     * @return
     */
    @Bean
    public ResourceServerTokenServices tokenServices(){
        RemoteTokenServices tokenServices = new RemoteTokenServices();
        tokenServices.setClientId("orderService");//在認證服務器配置的,訂單服務的clientId
        tokenServices.setClientSecret("123456");//在認證服務器配置的,訂單服務的ClientSecret
        tokenServices.setCheckTokenEndpointUrl("http://localhost:9090/oauth/check_token");
        //配置一個轉換器,將token信息轉換為用戶對象
        // TODO:獲取用戶信息本應該是認證服務器的事吧!總感覺在這里做不合適
        tokenServices.setAccessTokenConverter(getAccessTokenConverter());
        return tokenServices;
    }

    //轉換器,將token轉換為用戶信息
    private AccessTokenConverter getAccessTokenConverter() {
        DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
        //這個類的目的是設UserDetailsService,來將token轉換為用戶信息,不設默認為空
        DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter();
        userTokenConverter.setUserDetailsService(userDetailsService);
        accessTokenConverter.setUserTokenConverter(userTokenConverter);
        return accessTokenConverter;
    }

    /**
     * 要認證跟用戶相關的信息,一般用 AuthenticationManager
     * 覆蓋這個方法,可以將AuthenticationManager暴露為一個Bean
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        OAuth2AuthenticationManager authenticationManager = new OAuth2AuthenticationManager();
        authenticationManager.setTokenServices(tokenServices());//設置為自定義的TokenServices,去校驗令牌
        return authenticationManager;
    }

}
UserDetailsServiceImpl
package com.nb.security.resource.server;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

@Component("userDetailsService") //TODO:不
public class UserDetailsServiceImpl implements UserDetailsService {


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //這里就不去讀數據庫了
        User user = new User();
        user.setId(1L);
        user.setUsername(username);
        return user;
    }
}

User對象,實現UserDetails接口:

package com.nb.security.resource.server;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public class User implements UserDetails{

    private Long id;

    private String username;

    private String password;


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
    }


    @Override
    public boolean isAccountNonExpired() {
        return true;  //賬號沒過期
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;//賬號沒被鎖定
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;//密碼沒過期
    }

    @Override
    public boolean isEnabled() {
        return true;//是否可用
    }


    @Override
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }



}

然后在訂單Controller里,就可以取到用戶的 id等其他屬性了:

用 @AuthenticationPrincipal User user 注解可以取出User對象。

用 @AuthenticationPrincipal(expression = "#this.id") Long id  可以取出User里面的屬性

 

 

 代碼放在了github :https://github.com/lhy1234/springcloud-security/tree/chapt-4-6-config-persistence

下一節,說將token持久化到數據庫

歡迎關注個人公眾號一起交流學習:

 
        

 


免責聲明!

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



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