Spring Boot整合oauth2.0搭建統一授權服務(密碼模式)


前言

寫這個博客得原因是最近想要將自己得api單獨發布給第三方使用,但是又不想被別人濫用,所以想弄一個授權服務,但是網上關於oauth2.0的資料層出不窮,看了之后完全不明白應該如果實際的去整合,現在基本成功后記錄下來。
關於oauth2.0的概念以及相關的知識等可以建議參閱 理解OAuth 2.0

准備

新建一個Spring Boot的web項目並導入一下依賴:
<dependency>  
    <groupId>org.springframework.security.oauth</groupId>  
    <artifactId>spring-security-oauth2</artifactId>  
</dependency>  
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-security</artifactId>  
</dependency>  
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-web</artifactId>  
</dependency>  

配置

配置EnableAuthorizationServer

@Configuration  
@EnableAuthorizationServer  
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {  
  
  
    @Autowired  
    private AuthenticationManager authenticationManager;  
  
    @Autowired  
    private UserDetailsService userService;  
  
    @Autowired  
    private TokenStore tokenStore;  
  
    @Override  
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {  
        clients.inMemory()  
                .withClient("test")//客戶端ID  
                .authorizedGrantTypes("password", "refresh_token")//設置驗證方式  
                .scopes("read", "write")  
                .secret("123456")  
                .accessTokenValiditySeconds(10000) //token過期時間  
                .refreshTokenValiditySeconds(10000); //refresh過期時間  
    }  
  
    @Override  
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {  
        endpoints.tokenStore(tokenStore)  
                .authenticationManager(authenticationManager)  
                .userDetailsService(userService); //配置userService 這樣每次認證的時候會去檢驗用戶是否鎖定,有效等  
    }  
  
    @Bean  
    public TokenStore tokenStore() {  
        //使用內存的tokenStore  
        return new InMemoryTokenStore();  
    }  
}

UserService接口定義如下:

public interface UserService extends UserDetailsService {  
    //后期在此新增UserService的業務接口  
}  

其中UserDetailsService只包含一個需要實現的方法,具體實現:

@Primary  
@Service("userService")  
public class UserServiceImpl implements UserService {  
  
    private final static Set<User> users = new HashSet<>();  
  
    static {  
        users.add(new User(1, "test-user1", "123451"));  
        users.add(new User(2, "test-user2", "123452"));  
        users.add(new User(3, "test-user3", "123453"));  
        users.add(new User(4, "test-user4", "123454"));  
    }  
  
    @Override  
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {  
        Optional<User> user = users.stream()  
                .filter((u) -> u.getUserName().equals(s))  
                .findFirst();  
        if (!user.isPresent())  
            throw new UsernameNotFoundException("there's no user founded!");  
        else  
            return UserDetailConverter.convert(user.get());  
    }  
  
    private static class UserDetailConverter {  
        static UserDetails convert(User user) {  
            return new MyUserDetails(user);  
        }  
    }  
}  
根據方法名很容易明白spring 的組件會調用此方法去獲取到用戶的信息並去驗證。
這里的用戶信息直接寫死的,實際中可以用jdbc或者其他配置等方式。
同時loadUserByUsername方法要求返回一個UserDetails接口:
public interface UserDetails extends Serializable {  
    Collection<? extends GrantedAuthority> getAuthorities();  
  
    String getPassword();  
  
    String getUsername();  
  
    boolean isAccountNonExpired();  
  
    boolean isAccountNonLocked();  
  
    boolean isCredentialsNonExpired();  
  
    boolean isEnabled();  
} 
並且spring已經有了它的一個實現:org.springframework.security.core.userdetails.User類
由於User這個名字很容易和我們項目中的實體User重名這里選擇繼承這個類自己實現一個UserDetails:
/** 
 * 自定義UserDetails類 攜帶User實例 
 */  
public class MyUserDetails extends User {  
  
    private com.example.oauth.pojo.User user;  
  
    public MyUserDetails(com.example.oauth.pojo.User user) {  
        super(user.getUserName(), user.getPassword(), true, true, true, true, Collections.EMPTY_SET);  
        this.user = user;  
    }  
  
    public com.example.oauth.pojo.User getUser() {  
        return user;  
    }  
  
    public void setUser(com.example.oauth.pojo.User user) {  
        this.user = user;  
    }  
}  
到此基本的配置就已經完成了,

測試

寫一個測試的Controller:

 

@RestController  
public class UserController {  
  
    @Autowired  
    private TokenStore tokenStore;  
  
    @PostMapping("/bar")  
    public String bar(@RequestHeader("Authorization") String auth) {  
  
        MyUserDetails userDetails = (MyUserDetails) tokenStore.readAuthentication(auth.split(" ")[1]).getPrincipal();  
  
        User user = userDetails.getUser();  
  
        return user.getUserName() + ":" + user.getPassword();  
    }  
} 
啟動項目:
訪問:localhost:8080/bar
返回未授權

訪問:localhost:8080/oauth/token獲取token
這里的Authrization字段中Basic后面是配置中的clientId + ":" + secret的Base64編碼結果
我這里是:test:123456的Base64編碼結果
返回token信息:
使用token訪問controller:
成功。
版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/LightOfMiracle/article/details/79151074


免責聲明!

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



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