Spring Security oauth2 介紹

介紹:什麼是oAuth :oauth是一個協議,是爲用戶資源的授權提供一個安全的,開放而又簡易的標準,與以往的授權方式不同之處是,oauth的授權不會使第三方接觸到到第三方的賬號信息,即第三方無需使用用戶的用戶名與密碼就可以申請獲得該用戶的資源的授權,因此oauth 是安全的。

什麼是Security:Spring Security 是一個安全框架,能夠爲Spring企業應用系統提供聲明式的安全訪問控制,Spring Security基於Servlet過濾器,Ioc和Aop,爲Web請求和方法的調用提供身份確認和授權處理,避免了代碼的耦合,減少了大量的重複代碼。

交互過程:

 oauth 在客戶端 與服務提供商之間,設置了一個授權層,客戶端是不能直接登錄 服務提供商的,只能登錄授權層,從此將用戶與客戶端分來,客戶端登錄登錄授權層所用的令牌(Token),與用戶的密碼不同,用戶可以在登錄的時候,指定授權層令牌的權限範圍和有效期,客戶端 登錄授權層之後,服務提供商會根據令牌的權限範圍和有效期,想客戶端 開放用戶存儲的資料。

從上圖我們可以看出,在交互模型涉及的共有三方

 資源擁有者:用戶

 客戶端:App、瀏覽器等。。

 服務提供方:

     認證服務器

     資源服務器

 什麼是認證服務器:

    認證服務器負責對用戶進行認證,並授權給客戶端權限,認證很容易(驗證賬戶和密碼即可),問題在於如何授權,比如當我們使用第三方登陸時,比如qq,會直接跳轉到qq的登錄頁面,同時會有 授權 的字樣 

認證服務器在認證的時候,需要知道 請求授權 的客戶端的身份以及該客戶端的請求的權限,我們可以爲每一個客戶端預先分配一個id,並給每個id對應一個名稱以及權限的信息,這些信息可以寫在認證服務器上的配置文件中,然後,客戶端每次打開授權頁面的時候,把屬於自己的id傳遞過來,如下:

http://localhost:8080/login?client_id=yourClientId

但是隨着時間的推移和業務的增長,會發現,修改配置的工作消耗太多的人力。

oAuth2開放平臺

開放平臺是由oAuth2.0 協議衍生出的一個產品,他的作用就是讓客戶端自己去這面去註冊、申請、通過之後系統自動分配client_id ,並完成配置的自動更新(通常是寫進數據庫)。客戶端要完成申請,通常需要填寫客戶端程序的類型(Web。app等)、企業介紹,執照,想要獲取的權限等信息,這些信息在得到服務提供方的人工審覈通過之後,開放平臺會自動分配一個client_id給客戶端。

到這裏就實現登錄認證,授權頁的信息展示,那麼接下來,當用戶進行授權之後,認證服務器需要把產生的access_token 發送給客戶端,方案如下;

 讓客戶端開放平臺申請的時候,填寫一個URL,例如:http://localhost:8080/

  每次當用戶授權成功之後,認證服務器將頁面重定向到 這個URL(回調),並帶上access_token,例如:http://localhost:8080?access_token=123123

  客戶端接受到了這個 access_token 而且認證服務器的授權動作已經完成,剛好把程序的控制權交給客戶端,由客戶端決定接下來向用戶展示什麼內容。

下面講解什麼時候 Access Token :

  Access Token 是客戶端訪問資源服務器的令牌,擁有這個令牌代表得到用戶的授權,然而這個令牌是臨時的,有一定的有效期,這是因爲 Access Token 在使用過程會可能泄露,給Access token 限定一個較短的 有效期,可以降低因Access Token 泄露帶來的風險。

  但是在這樣引入有效期之後,客戶端使用起來就不方便,每當Access Token 過期,客戶端就必須重新向用戶索要授權,於是oAuth2.0引入了 Refresh token 的機制

Refresh Token

   Refresh Token 的作用是用用來刷新Access token 的,認證服務器提供一個刷新的接口,

http://localhost:8080/refresh?refresh_token=&client_id=

傳入 refresh_token 和 client_id ,認證服務器驗證通過之後,返回一個新的Access Token 爲了安全,oAuth2引入了兩個措施:

    oAuth2.0 要求,Refresh Token 一定 保存在客戶端的服務器上, 而覺不能存放在客戶端(app 、pc端軟件)上,調用refresh 接口的時候,一定是從 服務器到服務器的訪問。

    oauth2.0 引入了 client_secret 機制,即每一個 clieng_id 都對應一個clieng_secret ,這個clieng_secret 機制,即每一個clieng_id 都對應一個clieng_secret 一起分配給客戶端,客戶端 必須把 clieng_secret 妥善保存在服務器上,決不能泄露,在刷新Access Token時,需要驗證這個client_secret.

http://localhost:8080/refresh?refresh_token=&client_id=&client_secret=

這就是 Refresh Token 的機制,Refresh Token 的有效期非常長,會在用戶授權時,隨Access Token 一起重定向到回調URL 傳遞給客戶端

 

下面講解什麼是授權模式:

    客戶端在必須得到用戶的授權(authorization grant),才能獲取到令牌(access token)。oAuth2定義了四種授權方式

  implicit : 簡化模式,不推薦使用

  authorization code : 授權碼模式

  resource owner password credentials : 密碼模式

  client credentals : 客戶端模式

  簡化模式:

   簡化模式適合用於純靜態頁面的應用,所謂純靜態頁面的應用,也就是應用沒有在服務器上執行代碼的權限(通常就是吧代碼託管到別人服務器上),只有前端js 代碼的控制權,相當於只有h5 客戶端,沒有後臺,使用該模式,該模式中的Access Token 容易泄露,且不可刷新

授權碼模式:

   授權碼模式適用於自己的服務器i的應用,他是一個一次性的臨時憑證,用來換取access_token 和 refresh_token 認證服務器提供了一個類似這樣的接口,。

https://localhost:8080/exchange?code=&client_id=&client_secret=

 需要傳入 code 、client_id 以及 client_secret 驗證通過之後,返回Access_token 和 refresh_token ,一旦換取成功,code 立即作廢,不能在使用第二次。

  

這個code 的作用是保護Token 的安全性,簡單模式不安全的原因是,在第四步重定向將token返回給應用的時候,這一步容易v被攔截,但是在引入code 之後,即使獲取到code,但是由於無法獲取保存在服務器的client_secret ,因爲也無法通過code 換取token,在第五步,是服務器與服務器之間的訪問,所以不容易攔截,其次,這個請求通常是https的實現,即使能監聽到數據包也無法解析出內容。

使用場景: 不對外提供賬戶和密碼,自己使用賬戶和密碼

所以說有了這個code,token的安全性大大的提高,因此,oAuth2.0 鼓勵使用這種方式進行授權。

密碼模式:

  在密碼模式中,用戶向客戶端提供自己的用戶名和密碼,客戶端使用這些信息,想 服務商提供商所要授權,在這種模式下,用戶必須把自己的密碼給客戶端,但是客戶端不存儲密碼,這通常用在對客戶端高度信任的情況下,比如客戶端是操作系統的一部分。

該模式的使用場景:一個公司的兩個系統,登錄一個系統的時候同時登錄另外一個系統

在使用的時候,第2步中,認證服務器需要對客戶端的身份進行驗證,確保是受信任的客戶端

客戶端模式:

  兩個客戶端公用一個後端的模塊,沒有用戶界面的時候,可以用戶客戶端模式

下面的代碼是一個簡單的小案例,可以對Tocken 的刷新,獲取,然後訪問靜態資源數據,但是這些並沒有真正的與qq等第三方對接,後續的代碼還在更新中....

首選查看我的項目的結構:

首先是spring-security-oauth2 的 pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.funtl</groupId>
    <artifactId>spring-security-oathou2</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <url>http://www.funtl.com</url>

    <modules>
        <module>spring-security-oauth2-dependencies</module>
        <module>spring-security-oauth2-server</module>
        <module>spring-security-oauth2-resource</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <licenses>
        <license>
            <name>Apache 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        </license>
    </licenses>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.funtl</groupId>
                <artifactId>spring-security-oauth2-dependencies</artifactId>
                <version>${project.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <profiles>
        <profile>
            <id>default</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <spring-javaformat.version>0.0.7</spring-javaformat.version>
            </properties>
            <build>
                <plugins>
                    <plugin>
                        <groupId>io.spring.javaformat</groupId>
                        <artifactId>spring-javaformat-maven-plugin</artifactId>
                        <version>${spring-javaformat.version}</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <configuration>
                            <includes>
                                <include>**/*Tests.java</include>
                            </includes>
                            <excludes>
                                <exclude>**/Abstract*.java</exclude>
                            </excludes>
                            <systemPropertyVariables>
                                <java.security.egd>file:/dev/./urandom</java.security.egd>
                                <java.awt.headless>true</java.awt.headless>
                            </systemPropertyVariables>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-enforcer-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>enforce-rules</id>
                                <goals>
                                    <goal>enforce</goal>
                                </goals>
                                <configuration>
                                    <rules>
                                        <bannedDependencies>
                                            <excludes>
                                                <exclude>commons-logging:*:*</exclude>
                                            </excludes>
                                            <searchTransitive>true</searchTransitive>
                                        </bannedDependencies>
                                    </rules>
                                    <fail>true</fail>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-install-plugin</artifactId>
                        <configuration>
                            <skip>true</skip>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-javadoc-plugin</artifactId>
                        <configuration>
                            <skip>true</skip>
                        </configuration>
                        <inherited>true</inherited>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

    <repositories>
        <repository>
            <id>spring-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

總的一個依賴的管理是 spring-security-oauth2-dependencies 項目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.funtl</groupId>
    <artifactId>spring-security-oauth2-dependencies</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <url>http://www.funtl.com</url>

    <properties>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
        <spring-boot-mapper.version>2.1.5</spring-boot-mapper.version>
    </properties>

    <licenses>
        <license>
            <name>Apache 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        </license>
    </licenses>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.zaxxer</groupId>
                <artifactId>HikariCP</artifactId>
                <version>${hikaricp.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
                <exclusions>
                    <!-- 排除 tomcat-jdbc 以使用 HikariCP -->
                    <exclusion>
                        <groupId>org.apache.tomcat</groupId>
                        <artifactId>tomcat-jdbc</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper-spring-boot-starter</artifactId>
                <version>${spring-boot-mapper.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <repositories>
        <repository>
            <id>spring-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

</project>

注意當spring boot 在使用 2.1之後以後,spring cloud 是用G 開頭的,如果是2.0的需要使用F開頭的,要不然會出錯

spring-security-oauth2-server 是oauth2 的認證和授權的服務

查看pom 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.funtl</groupId>
        <artifactId>spring-security-oathou2</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>spring-security-oauth2-server</artifactId>

    <licenses>
        <license>
            <name>Apache 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        </license>
    </licenses>


    <dependencies>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>

        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <exclusions>
                <!-- 排除 tomcat-jdbc 以使用 HikariCP -->
                <exclusion>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-jdbc</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.funtl.springsecurityoauth2server.SpringSecurityOauth2ServerApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

這是所需要到的pom的依賴

我們首選查看 Spring security的配置

package com.funtl.springsecurityoauth2server.server.config;

import com.funtl.springsecurityoauth2server.server.config.service.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * R認證賬號是否有效
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {


    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    /** 該返回的類,在spring 中是存在的,所以需要重寫,換成自己的
     * @return
     */
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 基於內存的認證
//        auth
//                .inMemoryAuthentication()
//                .withUser("admin")
//                .password(passwordEncoder().encode("123456"))
//                .roles("ADMIN")
//                .and()
//                .withUser("user")
//                .password(passwordEncoder().encode("123456"))
//                .roles("USER");
        // 基於數據庫的認證
        auth.userDetailsService(userDetailsService());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 將指定端口,暴露出去,因爲在請求認證的時候,需要去訪問一個    check_token 的一個端口,
        // 如果不將 check_token 暴露出去,會出現403的錯誤
        web.ignoring().antMatchers("/oauth/check_token");
    }
}

上面的代碼我們可以看到,Spring boot  Security 提供了一個類。 WebSecurityConfigurerAdapter 該類是一個抽象的接口,

configure(AuthenticationManagerBuilder auth) : 該類是對用戶的認證

package com.funtl.springsecurityoauth2server.server.config.service;

import com.funtl.springsecurityoauth2server.server.domain.TbPermission;
import com.funtl.springsecurityoauth2server.server.domain.TbUser;
import com.funtl.springsecurityoauth2server.server.service.TbPermissionService;
import com.funtl.springsecurityoauth2server.server.service.TbUserService;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 完成用戶的認證與授權的工作,將用戶的信息和角色信息,全部交給 框架去管理
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {


    @Autowired
    private TbUserService tbUserService;

    @Autowired
    private TbPermissionService tbPermissionService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 查詢用戶的信息
        TbUser byUsername = tbUserService.getByUsername(username);
        List<GrantedAuthority> grantedAuthorityArrayList = Lists.newArrayList();
        //
        if (byUsername != null) {
            // 進行授權  查看是否有權限
            List<TbPermission> tbPermissions =
                    tbPermissionService.selectByUserId(byUsername.getId());
            if(tbPermissions.size() >0){
                tbPermissions.forEach(tbPermission -> {
                    if (tbPermission != null && tbPermission.getEnname() != null) {
                        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(tbPermission.getEnname());
                        grantedAuthorityArrayList.add(grantedAuthority);
                    }
                });
            }
        }
        return new User(byUsername.getUsername(), byUsername.getPassword(), grantedAuthorityArrayList);
    }
}

  將用於的信息,權限,交給框架去管理。

上面的步驟是進行認證,下面開始授權的操作。

package com.funtl.springsecurityoauth2server.server.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import javax.sql.DataSource;

/**
 * 授權
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {


    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    // 創建數據源

    /** 存儲 返回的 Tokin 數據
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore());
    }


    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource());
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        /*// 使用客戶端模式   需要知道那個客戶端 來進行請求
        clients.
                // 使用本地內存存儲
                        inMemory().
                // 發送的 clientId
                        withClient("client").
                // client_secret
                        secret(passwordEncoder.encode("secret")).
                // 授權的類型
                        authorizedGrantTypes("authorization_code")
                // 授權的範圍
                .scopes("app")
                // 回調的地址
                .redirectUris("http://localhost:8080/oauth2-server/controller/hello");*/

        //  使用jdbc 的方式,將數據庫中的數據進行獲取
        clients.withClientDetails(jdbcClientDetails());
    }

    @Bean
    public ClientDetailsService jdbcClientDetails() {
        return  new JdbcClientDetailsService(dataSource());
    }


}

Sql

CREATE TABLE `tb_permission` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `parent_id` bigint(20) DEFAULT NULL COMMENT '父權限',
  `name` varchar(64) NOT NULL COMMENT '權限名稱',
  `enname` varchar(64) NOT NULL COMMENT '權限英文名稱',
  `url` varchar(255) NOT NULL COMMENT '授權路徑',
  `description` varchar(200) DEFAULT NULL COMMENT '備註',
  `created` datetime NOT NULL,
  `updated` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8 COMMENT='權限表';
insert  into `tb_permission`(`id`,`parent_id`,`name`,`enname`,`url`,`description`,`created`,`updated`) values 
(37,0,'系統管理','System','/',NULL,'2019-04-04 23:22:54','2019-04-04 23:22:56'),
(38,37,'用戶管理','SystemUser','/users/',NULL,'2019-04-04 23:25:31','2019-04-04 23:25:33'),
(39,38,'查看用戶','SystemUserView','/users/view/**',NULL,'2019-04-04 15:30:30','2019-04-04 15:30:43'),
(40,38,'新增用戶','SystemUserInsert','/users/insert/**',NULL,'2019-04-04 15:30:31','2019-04-04 15:30:44'),
(41,38,'編輯用戶','SystemUserUpdate','/users/update/**',NULL,'2019-04-04 15:30:32','2019-04-04 15:30:45'),
(42,38,'刪除用戶','SystemUserDelete','/users/delete/**',NULL,'2019-04-04 15:30:48','2019-04-04 15:30:45'),
(44,37,'內容管理','SystemContent','/contents/',NULL,'2019-04-06 18:23:58','2019-04-06 18:24:00'),
(45,44,'查看內容','SystemContentView','/contents/view/**',NULL,'2019-04-06 23:49:39','2019-04-06 23:49:41'),
(46,44,'新增內容','SystemContentInsert','/contents/insert/**',NULL,'2019-04-06 23:51:00','2019-04-06 23:51:02'),
(47,44,'編輯內容','SystemContentUpdate','/contents/update/**',NULL,'2019-04-06 23:51:04','2019-04-06 23:51:06'),
(48,44,'刪除內容','SystemContentDelete','/contents/delete/**',NULL,'2019-04-06 23:51:08','2019-04-06 23:51:10');

CREATE TABLE `tb_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `parent_id` bigint(20) DEFAULT NULL COMMENT '父角色',
  `name` varchar(64) NOT NULL COMMENT '角色名稱',
  `enname` varchar(64) NOT NULL COMMENT '角色英文名稱',
  `description` varchar(200) DEFAULT NULL COMMENT '備註',
  `created` datetime NOT NULL,
  `updated` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8 COMMENT='角色表';
insert  into `tb_role`(`id`,`parent_id`,`name`,`enname`,`description`,`created`,`updated`) values 
(37,0,'超級管理員','admin',NULL,'2019-04-04 23:22:03','2019-04-04 23:22:05');

CREATE TABLE `tb_role_permission` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_id` bigint(20) NOT NULL COMMENT '角色 ID',
  `permission_id` bigint(20) NOT NULL COMMENT '權限 ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=48 DEFAULT CHARSET=utf8 COMMENT='角色權限表';
insert  into `tb_role_permission`(`id`,`role_id`,`permission_id`) values 
(37,37,37),
(38,37,38),
(39,37,39),
(40,37,40),
(41,37,41),
(42,37,42),
(43,37,44),
(44,37,45),
(45,37,46),
(46,37,47),
(47,37,48);

CREATE TABLE `tb_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '用戶名',
  `password` varchar(64) NOT NULL COMMENT '密碼,加密存儲',
  `phone` varchar(20) DEFAULT NULL COMMENT '註冊手機號',
  `email` varchar(50) DEFAULT NULL COMMENT '註冊郵箱',
  `created` datetime NOT NULL,
  `updated` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`) USING BTREE,
  UNIQUE KEY `phone` (`phone`) USING BTREE,
  UNIQUE KEY `email` (`email`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8 COMMENT='用戶表';
insert  into `tb_user`(`id`,`username`,`password`,`phone`,`email`,`created`,`updated`) values 
(37,'admin','$2a$10$9ZhDOBp.sRKat4l14ygu/.LscxrMUcDAfeVOEPiYwbcRkoB09gCmi','15888888888','[email protected]','2019-04-04 23:21:27','2019-04-04 23:21:29');

CREATE TABLE `tb_user_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL COMMENT '用戶 ID',
  `role_id` bigint(20) NOT NULL COMMENT '角色 ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8 COMMENT='用戶角色表';
insert  into `tb_user_role`(`id`,`user_id`,`role_id`) values 
(37,37,37);

下面直講解對於請求的攔截

package com.funtl.springsecurityoauth2resource.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true,jsr250Enabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {


    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.
                exceptionHandling()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/")
                .hasAnyAuthority("SystemContent")
                .antMatchers("/view/**").hasAuthority("SystemContentView")
                .antMatchers("/insert/**").hasAuthority("SystemContentInsert")
                .antMatchers("/update/**").hasAuthority("SystemContentUpdate")
                .antMatchers("/delete/**").hasAuthority("SystemContentDelete");
    }
}

具體的大概的操作如上,因爲沒有具體的頁面,所以我就不詳細說了,代碼我沒有上傳,需要的留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章