spring boot 實現單點登錄 single sign on 包括註冊、登錄、退出 功能(數據存在Mysql)非常詳細!!!

目錄

 

知識點:spring security 、oauth2、jpa 、thymeleaf      以及  spring  boot 框架的知識

各個知識點 起到的作用:

 機制

依賴

流程:

client(客戶端)

Auth-server(認證服務器包括資源服務器)

jpa部分

spring security 部分

還有很重要的一部分 Resource Server

thymeleaf部分


知識點:spring security 、oauth2、jpa 、thymeleaf      以及  spring  boot 框架的知識

希望初次接觸的同學去官網 搜索這些東西  看看一些簡單的demo      spring boot guides

先放 代碼    auth-server:   https://github.com/weitiancai/auth-server.git

                    client:   https://github.com/weitiancai/client.git     說明:需要先在 mysql 裏創建一個 名爲 autologin2 的數據庫

各位下載的時候順手給個小星星好不。。

概念:單點登錄         演示效果:  我b站第二個視屏。。    可以看到認證去了7778端口,完成後返回了7777端口。


各個知識點 起到的作用:

spring security :  對網頁訪問權限進行控制,你無權,你無法訪問。

oauth2:  授權的,這個“2”  的意思是,授權的是第二方,如,我們可以用qq賬號登錄很多網站,這個qq的授權服務相對於你要登錄的網站就是第二方。

 直白的說: oauth2 給用戶授權,spring security 根據你的權,開放給你頁面訪問,這個就是單點登錄的核心所在了

既然有第二方授權,那麼後臺的服務肯定不止一個,正如我上面提供的兩個git 項目地址一樣,我把整套機制彙總到了兩個服務裏面——1、客戶端 2、認證服務器(包括資源服務器)

thymeleaf  : 前端 框架 、和spring boot 比較契合好用,不用前後端分離開發

jpa : 和 mysql 數據交互用,可以根據代碼自動生成mysql 的表    (用過mybatis-plus 的同學會發現兩個東西的過程剛好相反)


 機制

其實sso 完整的機制就是  客戶端、認證服務器、資源服務器 這三塊         放張圖來證明我的觀點, oauth2 框架 原理

上面地址 是 來講述 oauth2 框架原理的,我沒仔細看(那也得有時間去看。。),我之前大把精力用來實現功能上了,而且這種封裝好的,除非你想改源代碼,知道不知道原理,實現起來 一樣的,但是大致過程肯定是要清楚地。

和shiro 框架採用token 認證不一樣, oauth 採用了從cookie 裏面獲取token的方法,只需要使用一次,並且一旦確定你的登錄合法,之後開放給你的網址權限就全部開放了,不會像shiro 一樣每次訪問一個接口都要帶上token。(我有什麼講錯的可以評論裏跟我講) 我把  resource server 和 authorization server 合爲一個服務,這是通用的做法。


依賴

client:

<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-oauth2</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</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-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

auth-server

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.3.RELEASE</version>
        </dependency>
    </dependencies>

 


突然發現要講的東西好多,我還是從功能點來一個個講吧。

流程:

 1、用戶訪問客戶端網址 --》2、用戶沒有登錄( 即網址沒有被授權) --》3、跳轉到auth-server (認證服務器,下面只寫英文)--》4、用戶註冊並登錄賬號密碼(併成功後)--》5、跳轉到原本想訪問的那個網站(此時有了訪問該網站的權限)

如果用戶關閉了瀏覽器,(並沒有清理cookie)則當用戶第二次訪問想要訪問的網站時,可以直接進入(cookie 裏保存的token未過期的情況)

如果用戶手動退出,則需要再次在auth-server 登錄賬號密碼訪問 網站。(其實就是主動讓cookie裏的token過期,並跳轉到登錄界面而已)


client(客戶端)

 

給網站授予訪問權限是  spring-security 乾的事情,在 client 項目裏的 OauthConfig 類 ,繼承 WebSecurityConfigurerAdapter 

重寫(@Override) 的 config (HttpSecurity http)  函數,就是自定義那些url 可以訪問,哪些 是要有權限才行

@EnableOAuth2Sso
@Configuration
public class OauthConfig extends WebSecurityConfigurerAdapter{
    @Value("${auth-server}/exit")
    private String logoutUrl;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/", "/login**")
                .permitAll()
                .anyRequest()
                .authenticated();
        http.logout()
                .logoutSuccessUrl(logoutUrl)
                .and().authorizeRequests().anyRequest().authenticated();
    }
}

一行行解釋,antMatcher  指 ant 路徑匹配法 知識點  表明所有匹配到這類 路徑的,我要乾點啥,

authorizeReuqests()   幹啥呢,看名字—— 需要權限,結合上面 那就是 所有 ‘/’ 開頭的都要要權限,所以基本都要權限了

而下面 幾行    

.antMatchers("/", "/login**")  對於這兩個路徑,
.permitAll()   所有用戶都可以訪問
.anyRequest()  任何請求
.authenticated();  都認證過了 (這個比較難理解,這麼說吧,爲了讓這些url 不用授權即可訪問,設計者就允許程序編寫者使用authenticted方法,將這些url先自定義爲已經過認證的網址,是不是很妙)

也就是說,開放   /   和  /login 這兩個爲可訪問的,所以我們訪問   /  地址的時候,redirect (重定向) 到了 index.html 頁面 代碼:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }


    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        super.addViewControllers(registry);

        registry.addViewController("/")
                .setViewName("forward:/index");

        registry.addViewController("/index");
        registry.addViewController("/secure");

    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/resources/");
    }

    @Bean
    public RequestContextListener requestContextListener() {
        return new RequestContextListener();
    }


    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

addViewController 裏面 就 註冊了   /  /index  /secure  這三個view  because  ‘/ ’ direct to ‘/index ’ and  the '/' is permited to access ,so you can visit the static resource —— index.html   but  you can't  visit  secure.html (英語真好~) 下面是資源文件夾內容。 我們要實現的就是在  index.html 點擊跳轉按鈕then  visit the secure.html    

正如上面所說,訪問不了 secure.html  ,你需權限,你還沒登錄,這怎麼辦呢,沒事,這個跳轉你只需要配置,我們加的Oauth2依賴就給你設計好了怎麼跳轉等細節問題., 其實仔細看代碼的話,可以看到 client 的 OauthConfig 類 有一個 註解

按Ctrl+左鍵  

可以看到包含了

表明這個是 Oauth2 的客戶端

yml 文件配置如下:

server:
  port: 7778
  context-path: /ui
  session:
    cookie:
      name: UISESSION

auth-server: http://localhost:7777/auth

security:
  basic:
    enabled: false
  oauth2:
    client:
      clientId: ClientId  #客戶端 id
      clientSecret: secret # 客戶端的 密碼
      accessTokenUri: ${auth-server}/oauth/token
      userAuthorizationUri: ${auth-server}/oauth/authorize
#      scope: read, write
      authorized-grant-types: authorization_code
    resource:
      userInfoUri: ${auth-server}/hello/principal


spring:
  thymeleaf:
    cache: false
debug: true

 本機的server.port   context-path  session.cookie.name

auth-server : 即爲 auth-server(認證服務器) 配置地址 端口   7777 

Oauth 相關 的  clientId  clientSecret   是爲了讓auth-server 能夠知道到你是自己人。。 auth-server 內部也要有這兩個

accessTokenUri: ${auth-server}/oauth/token
userAuthorizationUri: ${auth-server}/oauth/authorize
authorized-grant-types: authorization_code

這個是固定的,除非你自定義接口地址,作用就是 上面圖中的 token  cookie  拿來拿去的地址,很複雜的,詳細請看上面鏈接。

resource:
      userInfoUri: ${auth-server}/hello/principal

這個配置及其重要,這個resource 即 資源服務,這個資源其實是包括登錄的用戶的信息的,it's  very very very important!

雖然到時候auth-server 裏寫的接口很簡單,但那是框架設計的好。

好了,@EnableOauth2Sso +  application.yml 配置 ,登錄的認證(輸賬號密碼) 就會到auth-server :http://localhost:7777/auth 這裏來了,沒錯,就是這麼簡單,接下來將auth-server 了


Auth-server(認證服務器包括資源服務器)

在訪問client web網頁的時候,如果是需要授權,則在“檢查”裏的狀態值爲“302”  如我要點擊client 頁面的a標籤後,本應跳轉到相應的7778 端口的secure.html 頁面,可以發現去了auth-server (7777端口)的登錄界面,檢查(F12)看一下發生了什麼

 

 三個302 的狀態之後,到了一個200 狀態的login 頁面,302什麼意思,簡單的概括這個過程,就是服務器端發現你沒有認證,那麼就會給你經過一系列重定向網址到登錄界面,如果說你已經登錄過了,我們可以看看差別(還是那個鏈接點擊)

可以看到直接就進入了,其實因爲在客戶頓和服務器都保存了必要的cookie 和 session 數據的緣故,我們在推出,然後重新登錄,可以看到下面network 裏面 經歷了  一個authorize?xxx (紅框) login?xxx(藍框) 這兩個重定向網址的過程,我們可以猜測就是這兩個過程,分別在服務端和客戶端記錄了必要的信息,這是下次登錄直接可以進入的前提,除非這些信息過時了。

 好了,說一說,auth-server 的構造,原理

jpa部分

這個乏善可陳吧,其實定義好Entity類,一些註解我就不講了,主要是User類中  @ManyToMany(多對多關係)的註解需要一定得數據庫知識和對jpa 的理解。以爲實體只有兩個 —— user、role  其實還需要將這兩張表關聯起來,就用到了第三張表,其實就是我們學習數據庫課上ER圖裏面的 “關係”,ER圖裏面不僅實體可以生成一張表,關係也會成爲一張表(我數據庫的老師看到會感動的要死,我真的還記得~)

@ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles;

 所以這個註解、屬性的意思呢,就是我需要有這個 “user_role” 的關係(表),知識點來了,jpa根據 這個 名稱就知道,這是那兩張表的關係了!!!,你如果不信,可以試試,我沒試過,我在看一篇外國文章的時候偶然發現的,一下子讓我懂了這個註解的工作原理。 知道是那兩張表的關係,我們就需要設定 這個 關係(表) 裏的字段名稱爲什麼,如上,是user_id,  role_id 可是這兩個字段的類型分別是什麼呢,沒錯,就是 user 、role 表的主鍵啊,進而聯想到外鍵的定義,user_id,role_id 不就是兩個外鍵嗎,而且,其實這兩個字段還是user_role 表的兩個主鍵(主鍵可以是一組o)

爲了不下載代碼的小夥伴也能看的更清楚,我還是放一下這兩個Entity 的代碼吧:

role:

package com.gpch.login.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "role_id")
    private int id;
    @Column(name = "role")
    private String role;


    @Override
    public String toString() {
        return "Role{" +
                "id=" + id +
                ", role='" + role + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

 user:

package com.gpch.login.model;

//import javafx.scene.control.PopupControlBuilder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;

import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import java.util.Set;

@Data
@Builder
@AllArgsConstructor
@Entity
@Table(name = "user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "user_id")
    private Integer id;
    @Column(name = "email")
    @Email(message = "*Please provide a valid Email")
    @NotEmpty(message = "*Please provide an email")
    private String email;
    @Column(name = "password")
    @Length(min = 5, message = "*Your password must have at least 5 characters")
    @NotEmpty(message = "*Please provide your password")
    private String password;
    @Column(name = "name")
    @NotEmpty(message = "*Please provide your name")
    private String name;
    @Column(name = "last_name")
    @NotEmpty(message = "*Please provide your last name")
    private String lastName;
    @Column(name = "active")
    private int active;
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles;

    public User() {
    }

    public User(User users) {
        this.active = users.active;
        this.email = users.email;
        this.id = users.id;
        this.lastName = users.lastName;
        this.name = users.name;
        this.password = users.password;
        this.roles = users.roles;
    }

//    public static <B extends PopupControlBuilder<B>> PopupControlBuilder<B> builder() {
//        return null;
//    }


    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", email='" + email + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                ", lastName='" + lastName + '\'' +
                ", active=" + active +
                ", roles=" + roles +
                '}';
    }


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

    public void setIdNull(){
        this.id = null;
    }
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getActive() {
        return active;
    }

    public void setActive(int active) {
        this.active = active;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
}

然後 分別創建兩個repository 接口就可以使用jpa 提供的數據庫crud方法了

在application.yml 文件裏 添加配置

# ==============================================================
# = Hibernate ddl auto (create, create-drop, update)
# ==============================================================
spring.jpa.hibernate.ddl-auto = update

就可以在spring boot 運行的時候自動生成所需的mysql 的表了,沒錯,按照Entity自動生成對應table。理論上連數據庫的名字也是可以自動生成的,不過我沒找到響應的方法,所以還是需要手動先創建一個數據庫,如我一開始所說的。

spring security 部分

和client 端類似,下面  類 內部 config @Override 方法內部定義過濾規則(有點長)。

@Configuration
@Order(1)
@EnableWebSecurity
@EnableAuthorizationServer
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Override
    protected void configure(HttpSecurity http) throws Exception {
        // Ant模式通配符匹配
        http.
                authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/login","/oauth/authorize").permitAll()
                .antMatchers("/registration").permitAll()
                .antMatchers("/admin/**").hasAuthority("ADMIN").anyRequest()
                .authenticated().and()
//                .csrf().disable()
                .formLogin()
                .loginPage("/login").failureUrl("/login?error=true")
//                .defaultSuccessUrl("/admin/home")
                .defaultSuccessUrl(clientUrl)
//                .successHandler(successHandler())
                .usernameParameter("email")
                .passwordParameter("password")
                .and().logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/").and().exceptionHandling()
                .accessDeniedPage("/access-denied")

                .and()
                .requestMatchers()
                .antMatchers("/", "/login", "/oauth/authorize", "/oauth/confirm_access", "/exit")
                .and()
                .authorizeRequests()
                .antMatchers("/webjars/**").permitAll()
                .anyRequest().authenticated();
    }

可能有冗餘,因爲我參考了好多項目,所以先都拿過來用了,也可以看出我這之間嘗試的次數之多,真的是這裏的配置如果沒有人來指點,要話費整個項目編寫的整整一半時間!這個絕非危言聳聽。一行行來講,和client 一樣的就不講了

.antMatchers("/admin/**").hasAuthority("ADMIN").anyRequest()
.authenticated()   是/admin/ 開始的網址 需要 “ADMIN” 角色才能訪問,這個未來單點需要管理員界面就可以用到了
.formLogin()
                .loginPage("/login").failureUrl("/login?error=true")
//                .defaultSuccessUrl("/admin/home")
                .defaultSuccessUrl(clientUrl)    可以看到fromLogin() 指設定登錄界面,如果後面沒有跟 .loginPage(xxx)那麼就到默認登錄頁面去了,我們是自定義了一個login頁面(因爲默認頁面沒有註冊功能) 其實好多網上教程都是讓你進的默認login界面,這樣學的人就不能進行一些功能上的擴展了。   進而我們設置 失敗界面failureUrl、成功路徑defaultSuccessUrl 注意:這個成功路徑必須是我們client 端的響應路徑 即應該跳轉到的  localhost:7778/ui/secure  這樣才能回去,有的項目不用設置也可以回去,這個我沒有試過,但就是回不去。。 
.usernameParameter("email")
.passwordParameter("password")  這兩行制定了我們驗證用戶的方式,表明需要  用 email 和 password 來驗證,在哪裏驗證? 其實,你一開始是否有疑問,爲什麼我們可以自定義login登錄頁面,也可以使用默認的login頁面,這是因爲,無論選擇何種,最後都需要發送兩條信息 post 到 auth-server的 /login 地址,注意,是post  不是get  get /login 返回的是login 頁面, post /login  是將輸入的數據發送到 /login 接口  至於這兩條數據的id (待會兒 thymeleaf 裏面需要設置)即分別是 “email”,和 “password” ,默認情況下你也可以進入默認登錄頁面查看兩者id,以上,我覺得應該描述清楚這兩行的作用了。
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and().exceptionHandling()
.accessDeniedPage("/access-denied")  這裏呢,又是 一串重定向。。不過這裏是以後單點管理端可以使用的退出設置(和客戶端退出不一樣!!! ,聽到這裏你是不是也暈了,上面這個沒用到就不講了,客戶端退出過程先講)

這個退出按鈕代碼:

 可以看到post 到了 /logout 這個接口地址,其實這個接口(client 項目中) 和上面講的 /login 接口都是 spring security 提供給我們的,我們只需要配置 還記得上面我將client 項目  config 函數 裏的 http配置嗎,最後還有 退出的配置,下面紅框

設定退出成功 url  爲 logoutUrl  這個是在yml 文件裏的值(不懂? spring boot @Value 註解瞭解下) 

 我們看到是auth-server 地址了,也就是說,退出會跳轉到這個地址  localhost:7777/auth/exit

然後我們再來看 auth-server 的 exit 接口 ,在logoutController 類裏

@Controller

public class LogoutController {

    @RequestMapping("/exit")
    public void exit(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("here is exit");
        // token can be revoked here if needed  wonderful!!!
        // request obtain the token information and so on
        new SecurityContextLogoutHandler().logout(request, null, null);
        try {
            response.sendRedirect(request.getHeader("referer"));
            // 從哪來回哪去,經過上一步肯定還要驗證的
            // in ths case the header's referrer is 8080/notes
            // and because of the revoking token this url is not authenticated so it redirect to auth-server again
            // again key in username and password.
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

看的懂英文就看,這個退出還是參考國外一個大神的思路,new SecurityContextLogoutHandler().logout(request, null, null); 這一行,其實,就把auth-server 裏的相應session裏的token 給清空了,設爲了null, 可見之後用戶在訪問 需權限的網站就會 cookie裏的信息不匹配無法訪問, 然後try 塊裏  sendRedirect 方法 也是重定向,到 request.getHeader(“referer") 意思是請求頭裏的referer    其實就是從哪來回哪去,http header 裏的referer 指的就是這個網頁之前的網址地址,我們使用瀏覽器用的返回按鈕,其實找的就是這個referer,滿滿的知識點啊。。

這個referer 是什麼呢,來一張截圖: (我按了上面的退出 按鈕)

 過程如上,logout  -> exit -> secure  (就是那個referer)-->  login  

爲什麼會從secure 重定向到 login呢 ,你是不是懵逼了?

其實,從那一句new SecurityContextLogoutHandler().logout(request, null, null)  你就沒有權力再次訪問 secure 頁面了,所以一個沒有權限的你,就被整個世界安排到了 login頁面,還記得 client  裏的http配置嗎 我們只給 “/”  “/login**” 這兩個地址 設置了不需要權限的訪問,其他網址訪問需要授權,未授權則到auth-server 統一授權了才能再進去,可能會有人問,如果client 客戶端有多個了怎麼辦?  

事實上,我們可以定義多個返回值,根據不同的客戶端,手累,你們看一下這個網頁裏怎麼設置的   裏面截取一段

 哦,我現在也知道,這正是我不需要設置  .defaultSuccessUrl(clientUrl)  的原因了,它(框架)再確認賬號密碼爭取後 自動選擇跳轉的路勁,爲什麼是這個  xxx/login  是因爲  我們沒輸入賬號密碼之前, 點擊訪問secure 頁面時

,還是之前的截圖

 我們看到他是經過了      secure(被阻止)--》 /ui/login (就是中間過程)--》/authorize     

我們就是回到了這個  中間過程,然後再進入secure頁面。

還有一部分 SecurityConfiguation 類,是設置  Oauth2 的 ,也是極其重要,這裏挑選一個最重要配置函數

@Autowired
    private DataSource dataSource;

    @Value("${spring.queries.users-query}")
    private String usersQuery;

    @Value("${spring.queries.roles-query}")
    private String rolesQuery;
@Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
//        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());

        auth.
                jdbcAuthentication()
                .usersByUsernameQuery(usersQuery)
                .authoritiesByUsernameQuery(rolesQuery)
                .dataSource(dataSource)
                .passwordEncoder(bCryptPasswordEncoder);



//        auth.userDetailsService(getUserDetailsService()).passwordEncoder(bCryptPasswordEncoder);
//        auth.parentAuthenticationManager(authenticationManager)
//                .userDetailsService(customerUserDetailsService);
    }

 這裏用了  jdbcAuthentication() 方法,然後兩條語句也是自己寫的,說起來其實就是查找用戶姓名和角色,具體再配置文件裏

# ==============================================================
# = Spring Security / Queries for AuthenticationManagerBuilder
# ==============================================================
spring.queries.users-query=select email, password, active from user where email=?
spring.queries.roles-query=select u.email, r.role from user u inner join user_role ur on(u.user_id=ur.user_id) inner join role r on(ur.role_id=r.role_id) where u.email=?

 其實這裏有很多認證方法,包括UserDetailService 等等,我之前看到簡書裏面有個人寫的不錯,到時候把他的文章鏈接也放到這裏來好了,我就不再贅述。簡書文章:Spring Security(3)——進階篇(自定義身份驗證)(上)

還有很重要的一部分 Resource Server

記住,這個部分,我在國內還沒看到有人提過具體事項

因爲我在做單點登錄的過程中,遇到了登錄之後,跳轉不回之前頁面的問題,我在國內查找資料毫無進展,還在stackoverflow 上面提問了, 我的問題,結果在之後一次查閱資料的時候,也是在stackoverflow上找到了解決方法

 

就是這個回答,讓我恍然大悟,我在配置 自己的ResourceServer 類即下圖,沒有加上@EnableResourceServer

這個因爲Oauth2 版本問題? 我之前在國外網站學習的時候,是沒有這個註解的,比如  這個網站,有時需要翻牆才能訪問

這個也算一個大坑了。

所以,踩了這個坑,我才瞭解了這個resource server  存儲,並可以從中獲取用戶端的 cookie 信息,取出並與auth-server 進行比對等一系列之後纔會完成登錄之後的client、auth-server 用戶數據一致性。 

雖然配置所需代碼就那麼幾行。。。

thymeleaf部分

我感覺講了好多,這個部分我就很簡單的講講。

thyme leaf 和  spring boot 結合好,就體現在,你可以使用 modelAndView 對象,將數據呈現在對應的view(html頁面) 上面

比如get    一個 registration 頁面 

對應的viewname  = registration, 那麼這個就是 registration.html 文件了,可以看到加了一個“user” 的信息進去,那麼我們就可以再相應的html文件裏獲取到這個信息,這裏其實使用了一個表單

到時候表單發送,就把整個user 對象發送到對應接口

視圖層面和 controller 層的交互就都是類似的實現,上面的例子還是比較複雜的一種,簡單的單獨加個內容什麼的,項目裏面也是很好找的。

 

總結:

我感覺還有好多知識點沒有講,實在是東西有點複雜,我本人也是還在研究階段。

日後再有改進,或有其它任何問題,繼續再更

over

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