シングル・サインオンのログイン、登録を含む、シングルサインオンを実現するためのスプリングブーツは、非常に詳細に機能(プレゼンスMySQLのデータを)やめます!!!

ディレクトリ

 

知識:知識春のセキュリティ、のOAuth2、JPA、thymeleafと春ブートフレームワーク

知識ポイントの役割:

 メカニズム

頼ります

プロセス:

クライアント(クライアント)

(認証サーバのリソースサーバを含む)認証サーバー

JPA一部

春のセキュリティセクション

リソースサーバのもう一つの非常に重要な部分

一部thymeleaf


知識:知識春のセキュリティ、のOAuth2、JPA、thymeleafと春ブートフレームワーク

学生との最初の接触は、これらのものは、簡単なデモを見公式ウェブ検索に行きたい       春ブートガイドを

まず、コード・サーバーの認証を入れて:    https://github.com/weitiancai/auth-server.git

                    クライアント:    https://github.com/weitiancai/client.git      説明:MySQLではautologin2という名前のデータベースを作成する必要

あなたが本当に掘るために小さな星をダウンロードします。

コンセプト:シングルサインオン          効果のデモンストレーション:   私はB第2のビデオ画面を立ちます。    認定は、ポートに7777の復帰が完了した後、7778ポートに見ることができます。


知識ポイントの役割:

春のセキュリティは:   Webページへのアクセスを制御するために、あなたは権利はない、あなたがアクセスすることはできません。

OAuth2:   我々はQQのアカウントを持つサイトの多くをログに記録することができますよう、「2」、第二者によって承認されている意味、認定、あなたがログインしたいサイトに認定サービスQQの相対は、第二のパーティです。

 言うことは簡単:  許可されたユーザへのOAuth2、春のセキュリティ右手に基づいて、あなたが訪問ページに開放、これはコアのシングルサインがある場合

リソースを含む1、クライアント2、認証サーバ( - 第二者認証は、確かに、バックエンドサービスよりも、上記の私のGitのプロジェクトアドレスの2として、私は内部の2つのサービスに機構全体をまとめ、そこにあるので、サーバー)

Thymeleaf  :フロントエンドフレーム、およびスプリングブーツフィット比較簡単に、開発せずに、セパレータの前後端

JPA:MySQLとのデータが自動的にコード表のmysqlに応じて生成することが可能との対話(使用MyBatisのプラス学生は二つの対向するプロセスの何かを見つけるでしょう)


 メカニズム

実際には、完全なメカニズムのSSOは、私のポイントを証明するためにこれら三つのマップシートを置くために、クライアント、認証サーバ、サーバリソース、ある  原則の枠組みのOAuth2

あなたがソースを変更する場合を除き、上記のアドレスは、私は関数に多くのエネルギーを実現する前に、(それは...見るために時間を持っている必要があります)を注意深く見ており、このパッケージといいませんでした、原則の物語のOAuth2枠組みを伝えることですコードは、同じことを実現するために、原則を知っているかわからないが、一般的なプロセスは、明確にすることは確かです。

そして、トークン認証フレームワークを使用して史郎が内部クッキーから取得する方法を使用して、OAuthのトーク​​ン同じではありませんが、一度だけ使用され、あなたが合法的なログインを決定し、その後、すべてのアクセス許可を開くために、Webサイトを開いたら、史郎が好きではありませんインターフェイスへのすべての訪問はトークンを持参しなければなりません。私は一般的に行われている1つのサービスへのリソースサーバと認証サーバを置く(私は私に教えて、コメントについて話と間違って何もありません)。


頼ります

クライアント:

<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>

認証サーバー

<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から来る、について話をする多くのことを発見しました。

プロセス:

 1は、クライアントのウェブサイトへのユーザアクセス - 「2は、ユーザーがログインしていない 3、 - (つまりは、URLが許可されていない)」からサーバへの認証ジャンプ(認証サーバ、英語のみで、次の書き込み) - 「4、ユーザ登録をし、ログインアカウントのパスワード(と成功の後) - 「5、そのサイトにジャンプするには訪問したいと考えていました(サイトへのアクセスで、この時間を)

ユーザーがブラウザを閉じて(とクッキーを掃除していない)場合は、サイトのユーザーへの第二の訪問は、アクセスしたいときに、あなたが直接行くことができます(トークンを保存するためにクッキーの場合には有効期限が切れていません)

ユーザーが手動で終了した場合は、認証サーバーでサイトにアクセスするためのアカウントのパスワード再ログインする必要があります。(実際には、トークンのクッキーの有効期限が切れる作り、そして唯一のログイン画面にジャンプするためのイニシアチブをとります)


クライアント(クライアント)

 

サイトへのアクセス許可は、物事を行うには、スプリング・セキュリティ、継承WebSecurityConfigurerAdapterでOauthConfigクラスクライアント・プロジェクトであります 

仕事の権利を持つことになるが、これらのカスタムURLにアクセスすることができますされて書き換え(@Override)設定の(HttpSecurity HTTP)機能、

@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が一致アリのパスを指しラインの説明によるライン  の知識は、   これらのすべてがパスに一致していることを示し、私はDianshaをしたいです、

authorizeReuqests()それをやって、名前を見て - 上記と組み合わせる必要な権限は、すべての「/」権利が先頭になければならないということであるので、基本的に我々は権限を持っています

次の行    

.antMatchers("/", "/login**")  对于这两个路径,
.permitAll()   所有用户都可以访问
.anyRequest()  任何请求
.authenticated();  都认证过了 (这个比较难理解,这么说吧,为了让这些url 不用授权即可访问,设计者就允许程序编写者使用authenticted方法,将这些url先自定义为已经过认证的网址,是不是很妙)

言い換えれば、2アクセス可能に開放/と/ログインは、私たちは/時間アドレスにアクセスし、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();
    }
}

「index.htmlをしかしすることができます - 「/」「は/インデックス」と「/」への直接のアクセスにpermitedされているため、あなたは静的リソースを訪問することができますので、/ /インデックス/安全な3つのビューを登録しているaddViewControllerトン訪問secure.html(英語素敵〜)次は、リソースフォルダの内容です。私たちは、達成したい、その後secure.htmlを訪問したindex.htmlでジャンプボタンをクリックすることです    

前述したように、アクセスがsecure.htmlことができない、あなたは許可を必要とする、あなたは、それを行う方法を、すべての権利をでログインしていない、あなただけのこのジャンプを設定する必要があり、我々はなど、あなたが良いデザインのジャンプどのようにのOAuth2依存追加与えます詳細は、実際には、コードをよく見てみると、あなたは、クライアントの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コンテキストパスsession.cookie.nameネイティブ

認証サーバー:アドレスポート7777を設定するには、認証サーバー(認証サーバ)であります 

Oauth関連のclientId clientSecretは、あなたが私たちの一つであることを知ることができるように認証サーバーを有効にすることです。内部認証サーバーには2を持っている必要があります

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

あなたは、インターフェイスアドレスをカスタマイズしない限り、これは、固定され、トークンクッキーの役割は、上記のリンクのアドレス、非常に複雑で、詳細な外観を取るために使用上の図です。

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

この構成では、実際にユーザ情報に記録されます。このリソースを含むリソース・サービスを、である。このリソースは、それは非常に非常に非常に重要だということが非常に重要です!

認証サーバーのインタフェースを記述するための時間は非常に簡単ですが、それは良好なフレームデザインですが。

好了,@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

おすすめ

転載: blog.csdn.net/qq_38190111/article/details/90549567