spring boot 实现单点登录 single sign on 包括注册、登录、退出 功能(数据存在Mysql)非常详细!!!

6 篇文章 0 订阅
4 篇文章 0 订阅

目录

 

知识点: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

  • 14
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Security可以通过多种方式实现单点登录,其中最常用的是使用Spring Security SAML扩展来实现。具体步骤如下: 1. 配置Spring Security SAML扩展:在Spring Security配置文件中添加SAML扩展的依赖和配置。 2. 配置身份提供者:在SAML配置文件中配置身份提供者,包括身份提供者的元数据和证书。 3. 配置服务提供者:在SAML配置文件中配置服务提供者,包括服务提供者的元数据和证书。 4. 配置单点登录:在SAML配置文件中配置单点登录包括单点登录的URL和断言消费服务。 5. 配置用户认证:在SAML配置文件中配置用户认证,包括用户认证的方式和用户信息的获取。 6. 配置单点注销:在SAML配置文件中配置单点注销,包括单点注销的URL和注销请求的处理。 7. 配置安全策略:在SAML配置文件中配置安全策略,包括加密和签名的方式和算法。 通过以上步骤,可以使用Spring Security SAML扩展实现单点登录。具体实现过程需要根据具体的应用场景和需求进行调整和优化。 ### 回答2: Spring Security是一个功能强大且灵活的安全性解决方案,可以用于实现单点登录Single Sign-On,简称SSO)。 单点登录是指用户只需登录一次,即可在多个相互信任的应用系统中进行访问。Spring Security提供了多种方法来实现单点登录。 其中一种常见的实现方式是使用基于令牌(Token)的认证和授权机制。当用户登录成功后,系统会为该用户生成一个唯一的令牌,并将该令牌保存到用户的会话中。当用户访问其他系统时,这些系统会验证用户的令牌是否有效,并根据令牌中的信息进行认证和授权。 Spring Security提供了一套完整的认证和授权机制,可以很方便地实现上述的基于令牌的单点登录。在Spring Security中,可以将令牌保存在内存、数据库或者分布式存储中,以实现多个应用系统之间的共享。 另外,Spring Security还支持使用OAuth2协议来实现单点登录OAuth2是一种开放标准的授权协议,可以让用户授权第三方应用访问其在其他应用中的信息,从而实现单点登录Spring Security提供了OAuth2的实现,可以轻松地将其集成到应用中,实现跨系统的认证和授权。 除了上述方法,Spring Security还可以与其他单点登录框架(如CAS)进行集成,以实现更复杂的单点登录场景。 总之,Spring Security提供了多种方法来实现单点登录,开发者可以根据实际需求进行选择和配置。无论是基于令牌的单点登录还是使用OAuth2协议,Spring Security都能够提供强大的安全性保障,确保用户的登录信息和资源得到有效的保护。 ### 回答3: Spring Security可以实现单点登录Single Sign-On,简称SSO),即用户只需登录一次就可以访问多个相互信任的系统。 实现SSO的关键是集中式的认证和授权管理。Spring Security提供了多种方式来实现SSO,以下是一种常见的实现方式: 1. 配置认证中心:在一个独立的系统中,配置认证中心,负责用户的登录认证和鉴权。可以使用Spring Security提供的功能实现认证中心,如使用数据库存储用户信息和权限信息。 2. 配置SSO客户端:在需要使用SSO的系统中,添加SSO客户端配置。通过配置SSO客户端可以将用户登录请求转发到认证中心进行认证。在Spring Security中,可以使用SAML(Security Assertion Markup Language)或者OAuth2等协议来实现SSO。 3. 配置认证中心和SSO客户端的信任关系:在认证中心和SSO客户端之间建立信任关系,使其可以安全地进行认证和授权操作。可以使用数字证书、密钥对等方式来实现信任关系的建立。 4. 配置认证中心和SSO客户端的单点登录:通过配置认证中心和SSO客户端的单点登录相关的参数,实现用户只需在认证中心登录一次,就可以访问到其他相互信任的系统。用户在访问其他系统时,SSO客户端会将用户的认证信息发送给认证中心进行验证,从而实现单点登录。 总结来说,Spring Security可以通过配置认证中心和SSO客户端,并建立信任关系,实现单点登录功能。通过这种方式,用户只需登录一次就可以访问多个相互信任的系统,提高了用户体验和系统安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值