此文章篇幅较长,平日上班较少时间写作,请见谅。持续更新中。。。


oAuth2.0系列文章目录

#mermaid-svg-AZMPq56OmFj1I7k0 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-AZMPq56OmFj1I7k0 .error-icon{fill:#552222;}#mermaid-svg-AZMPq56OmFj1I7k0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AZMPq56OmFj1I7k0 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-AZMPq56OmFj1I7k0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AZMPq56OmFj1I7k0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AZMPq56OmFj1I7k0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AZMPq56OmFj1I7k0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AZMPq56OmFj1I7k0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AZMPq56OmFj1I7k0 .marker.cross{stroke:#333333;}#mermaid-svg-AZMPq56OmFj1I7k0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AZMPq56OmFj1I7k0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-AZMPq56OmFj1I7k0 .cluster-label text{fill:#333;}#mermaid-svg-AZMPq56OmFj1I7k0 .cluster-label span{color:#333;}#mermaid-svg-AZMPq56OmFj1I7k0 .label text,#mermaid-svg-AZMPq56OmFj1I7k0 span{fill:#333;color:#333;}#mermaid-svg-AZMPq56OmFj1I7k0 .node rect,#mermaid-svg-AZMPq56OmFj1I7k0 .node circle,#mermaid-svg-AZMPq56OmFj1I7k0 .node ellipse,#mermaid-svg-AZMPq56OmFj1I7k0 .node polygon,#mermaid-svg-AZMPq56OmFj1I7k0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AZMPq56OmFj1I7k0 .node .label{text-align:center;}#mermaid-svg-AZMPq56OmFj1I7k0 .node.clickable{cursor:pointer;}#mermaid-svg-AZMPq56OmFj1I7k0 .arrowheadPath{fill:#333333;}#mermaid-svg-AZMPq56OmFj1I7k0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AZMPq56OmFj1I7k0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AZMPq56OmFj1I7k0 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-AZMPq56OmFj1I7k0 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-AZMPq56OmFj1I7k0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AZMPq56OmFj1I7k0 .cluster text{fill:#333;}#mermaid-svg-AZMPq56OmFj1I7k0 .cluster span{color:#333;}#mermaid-svg-AZMPq56OmFj1I7k0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AZMPq56OmFj1I7k0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

oAuth2.0系列文章目录
一. 基于oAuth2.0开发属于自己的单点登录SSO授权服务 - 授权码Authourization Code模式

#mermaid-svg-KrjBsB7wvuoA53uB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-KrjBsB7wvuoA53uB .error-icon{fill:#552222;}#mermaid-svg-KrjBsB7wvuoA53uB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KrjBsB7wvuoA53uB .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-KrjBsB7wvuoA53uB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KrjBsB7wvuoA53uB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KrjBsB7wvuoA53uB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KrjBsB7wvuoA53uB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KrjBsB7wvuoA53uB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KrjBsB7wvuoA53uB .marker.cross{stroke:#333333;}#mermaid-svg-KrjBsB7wvuoA53uB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KrjBsB7wvuoA53uB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KrjBsB7wvuoA53uB .cluster-label text{fill:#333;}#mermaid-svg-KrjBsB7wvuoA53uB .cluster-label span{color:#333;}#mermaid-svg-KrjBsB7wvuoA53uB .label text,#mermaid-svg-KrjBsB7wvuoA53uB span{fill:#333;color:#333;}#mermaid-svg-KrjBsB7wvuoA53uB .node rect,#mermaid-svg-KrjBsB7wvuoA53uB .node circle,#mermaid-svg-KrjBsB7wvuoA53uB .node ellipse,#mermaid-svg-KrjBsB7wvuoA53uB .node polygon,#mermaid-svg-KrjBsB7wvuoA53uB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KrjBsB7wvuoA53uB .node .label{text-align:center;}#mermaid-svg-KrjBsB7wvuoA53uB .node.clickable{cursor:pointer;}#mermaid-svg-KrjBsB7wvuoA53uB .arrowheadPath{fill:#333333;}#mermaid-svg-KrjBsB7wvuoA53uB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KrjBsB7wvuoA53uB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KrjBsB7wvuoA53uB .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-KrjBsB7wvuoA53uB .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-KrjBsB7wvuoA53uB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KrjBsB7wvuoA53uB .cluster text{fill:#333;}#mermaid-svg-KrjBsB7wvuoA53uB .cluster span{color:#333;}#mermaid-svg-KrjBsB7wvuoA53uB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KrjBsB7wvuoA53uB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

基于oAuth2.0开发属于自己的单点登录SSO授权服务 - 授权码Authourization Code模式 .
应用场景
开发环境
客户端应用和授权服务器端属于同一个集团, 处于不同微服务Micro Service内
后端: Java8, Spring Boot, Spring Security, Spring AOP, BouncyCastle, MySQL ..
前端: Vue 3, Element, Axios, Router
其他: Nginx反向代理, 国密SM2, SM4加密算法 ..

文章目录

  • 前言
  • 一、具体实现及流程
    • 用户在授权服务器注册用户(Happy Flow)
    • 用户登录SSO(Happy Flow)
  • 二、具体实现步骤
    • 1. 项目设置
      • 1.1 引入Maven依赖库
      • 1.2 设置application.yml 和 application.properties
        • - application.yml
        • - application.properties
    • 2. 后端开发
      • 2.1 创建Login Controller
      • 2.2 创建POJO - CsrfTokenJSessionId
      • 2.3 创建index.html (基于Webjars Bootstrap and jQuery)
        • signin.js
  • 总结
  • 源代码
  • 码农经典语录
  • 参考链接

前言

本文用最基本的Spring Security,Spring Boot,不采用Spring Boot oAuth相关插件,重写oAuth2.0 SSO授权服务器。应用场景:客户端应用和授权服务器端属于同一个集团,处于不同微服务内;授权服务器和资源服务器处于相同服务器内。

一、具体实现及流程

用户在授权服务器注册用户(Happy Flow)

#mermaid-svg-zZs5onXGxCYBS0v7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-zZs5onXGxCYBS0v7 .error-icon{fill:#552222;}#mermaid-svg-zZs5onXGxCYBS0v7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zZs5onXGxCYBS0v7 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-zZs5onXGxCYBS0v7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zZs5onXGxCYBS0v7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zZs5onXGxCYBS0v7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zZs5onXGxCYBS0v7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zZs5onXGxCYBS0v7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zZs5onXGxCYBS0v7 .marker.cross{stroke:#333333;}#mermaid-svg-zZs5onXGxCYBS0v7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zZs5onXGxCYBS0v7 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zZs5onXGxCYBS0v7 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-zZs5onXGxCYBS0v7 .actor-line{stroke:grey;}#mermaid-svg-zZs5onXGxCYBS0v7 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-zZs5onXGxCYBS0v7 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-zZs5onXGxCYBS0v7 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-zZs5onXGxCYBS0v7 .sequenceNumber{fill:white;}#mermaid-svg-zZs5onXGxCYBS0v7 #sequencenumber{fill:#333;}#mermaid-svg-zZs5onXGxCYBS0v7 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-zZs5onXGxCYBS0v7 .messageText{fill:#333;stroke:#333;}#mermaid-svg-zZs5onXGxCYBS0v7 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zZs5onXGxCYBS0v7 .labelText,#mermaid-svg-zZs5onXGxCYBS0v7 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-zZs5onXGxCYBS0v7 .loopText,#mermaid-svg-zZs5onXGxCYBS0v7 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-zZs5onXGxCYBS0v7 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-zZs5onXGxCYBS0v7 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-zZs5onXGxCYBS0v7 .noteText,#mermaid-svg-zZs5onXGxCYBS0v7 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-zZs5onXGxCYBS0v7 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zZs5onXGxCYBS0v7 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zZs5onXGxCYBS0v7 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zZs5onXGxCYBS0v7 .actorPopupMenu{position:absolute;}#mermaid-svg-zZs5onXGxCYBS0v7 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-zZs5onXGxCYBS0v7 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zZs5onXGxCYBS0v7 .actor-man circle,#mermaid-svg-zZs5onXGxCYBS0v7 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-zZs5onXGxCYBS0v7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户 客户端 授权服务器 数据库 访问客户端页面,发起SSO注册请求 1 获取 csrfToken, jSessionId,sm4salt 2 返回 csrfToken, jSessionId,sm4salt 3 利用sms短信验证码 / 电邮验证码,验证用户手机号码 / 电邮地址 4 利用bcrypt加密用户密码 5 利用SM4加密算法和自定义方式组合csrfToken, sm4salt生成密码 6 发起用户注册请求 7 loop [pre-registration] 验证客户端安全信息(appId,appSecret,callback url,scope等等) 8 验证成功,写入用户 9 返回注册结果 10 注册成功 11 客户 客户端 授权服务器 数据库

用户登录SSO(Happy Flow)

#mermaid-svg-jmoOw1V8O9TOSdu5 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jmoOw1V8O9TOSdu5 .error-icon{fill:#552222;}#mermaid-svg-jmoOw1V8O9TOSdu5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jmoOw1V8O9TOSdu5 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-jmoOw1V8O9TOSdu5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jmoOw1V8O9TOSdu5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jmoOw1V8O9TOSdu5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jmoOw1V8O9TOSdu5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jmoOw1V8O9TOSdu5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jmoOw1V8O9TOSdu5 .marker.cross{stroke:#333333;}#mermaid-svg-jmoOw1V8O9TOSdu5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jmoOw1V8O9TOSdu5 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jmoOw1V8O9TOSdu5 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-jmoOw1V8O9TOSdu5 .actor-line{stroke:grey;}#mermaid-svg-jmoOw1V8O9TOSdu5 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-jmoOw1V8O9TOSdu5 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-jmoOw1V8O9TOSdu5 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-jmoOw1V8O9TOSdu5 .sequenceNumber{fill:white;}#mermaid-svg-jmoOw1V8O9TOSdu5 #sequencenumber{fill:#333;}#mermaid-svg-jmoOw1V8O9TOSdu5 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-jmoOw1V8O9TOSdu5 .messageText{fill:#333;stroke:#333;}#mermaid-svg-jmoOw1V8O9TOSdu5 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jmoOw1V8O9TOSdu5 .labelText,#mermaid-svg-jmoOw1V8O9TOSdu5 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-jmoOw1V8O9TOSdu5 .loopText,#mermaid-svg-jmoOw1V8O9TOSdu5 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-jmoOw1V8O9TOSdu5 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-jmoOw1V8O9TOSdu5 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-jmoOw1V8O9TOSdu5 .noteText,#mermaid-svg-jmoOw1V8O9TOSdu5 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-jmoOw1V8O9TOSdu5 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jmoOw1V8O9TOSdu5 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jmoOw1V8O9TOSdu5 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jmoOw1V8O9TOSdu5 .actorPopupMenu{position:absolute;}#mermaid-svg-jmoOw1V8O9TOSdu5 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-jmoOw1V8O9TOSdu5 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jmoOw1V8O9TOSdu5 .actor-man circle,#mermaid-svg-jmoOw1V8O9TOSdu5 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-jmoOw1V8O9TOSdu5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户 客户端 授权服务器 资源服务器 数据库 访问客户端页面,发起SSO登录请求 1 获取 csrfToken, jSessionId,sm4salt 2 返回 csrfToken, jSessionId,sm4salt 3 发起登录请求 4 验证客户端用户安全信息(appId,appSecret,callback url,scope等等) 5 loop 验证用户 6 查询及验证用户 7 用户验证成功 8 根据callback url值,发起请求并返回用户信息、角色及相关权限 9 写入用户登录状态及用户权限到sessionStorage 10 loop 客户 客户端 授权服务器 资源服务器 数据库

二、具体实现步骤

1. 项目设置

1.1 引入Maven依赖库

<!-- Core Functions Dependencies -->
<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>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency><!-- Web Modules Dependencies -->
<dependency><groupId>org.apache.tomcat</groupId><artifactId>tomcat-juli</artifactId><version>${tomcat.version}</version>
</dependency>
<dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>5.1.3</version>
</dependency>
<dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>3.6.0</version>
</dependency>
<dependency><groupId>org.webjars</groupId><artifactId>jquery-ui</artifactId><version>1.13.0</version>
</dependency>
<dependency><groupId>org.webjars</groupId><artifactId>font-awesome</artifactId><version>5.15.4</version>
</dependency>
<dependency><groupId>org.webjars</groupId><artifactId>webjars-locator-core</artifactId>
</dependency><!-- DB and Data Dependencies -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>
<!-- END Spring Boot default jdbc connector --><!-- Other Functions Dependencies -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>

1.2 设置application.yml 和 application.properties

- application.yml
server:port: 12911servlet:context-path: /oauth2
spring:profiles:active:- defaultapplication:name: hp-auth-oauth2-sso-api-12911
- application.properties
#spring.datasource.url=jdbc:mysql://192.168.31.54:3306/PRIVILEGE?useSSL=false&useUnicode=true&characterEncoding=utf8
spring.datasource.url=jdbc:mysql://[your domain name]:3306/[your db name]?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.username=[your db username]
spring.datasource.password=[your db password]
# Hikari will use the above plus the following to setup connection pooling
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=DatebookHikariCP
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.connection-test-query=SELECT 1
#"none", This is the default for MySQL, no change to the database structure.
#update Hibernate changes the database according to the given Entity structures.
#create Creates the database every time, but don't drop it when close.
#create-drop Creates the database then drops it when the SessionFactory closes.
#It is good security practice that after your database is in production state,
#  you make this none and revoke all privileges from the MySQL user connected to the Spring application,
#  then give him only SELECT, UPDATE, INSERT, DELETE.
spring.jpa.hibernate.ddl-auto=none
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.show-sql=true
#Unfortunately, Open Session in View (OSIV) is enabled by default in Spring Boot.
#So, make sure that setting: "spring.jpa.open-in-view=false"
#so that you can handle the LazyInitializationException the right way.
spring.jpa.open-in-view=false# Hibernate properties
spring.jpa.properties.hibernate.id.new_generator_mappings=false#thymelead properties
spring.mvc.static-path-pattern=/static/**
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.cache=false
spring.thymeleaf.enabled=true

2. 后端开发

2.1 创建Login Controller

package com.hivesplace.templates.controllers;import javax.servlet.http.HttpServletRequest;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;import com.hivesplace.templates.VOs.CsrfTokenJSessionIdVO;
import com.hivesplace.templates.beans.CsrfTokenJSessionId;@Controller
public class LoginController {@AutowiredCsrfTokenJSessionIdVO csrfTokenJSessionIdVO;@GetMapping(path="/login")public String login(HttpServletRequest request) {csrfTokenJSessionIdVO.setCsrfToken(new CsrfTokenJSessionId().getCsrfToken());csrfTokenJSessionIdVO.setJSessionId(request.getSession().getId());System.out.println(">>>>>>>>>>> csrfTokenJSessionVO: "+csrfTokenJSessionIdVO.toString());return "login";}
}

2.2 创建POJO - CsrfTokenJSessionId

package com.hivesplace.templates.beans;import java.util.Random;import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.stereotype.Component;import lombok.Data;@Data
@Component
public class CsrfTokenJSessionId {public CsrfTokenJSessionId() {this.setCsrfToken();this.jSessionId = "[please provide jSessionId by calling setter function - setJSessionId(String)]";}public CsrfTokenJSessionId(String csrfToken, String jSessionId) {this.csrfToken = csrfToken;this.jSessionId = jSessionId;}private String csrfToken;private String jSessionId;public void setCsrfToken() {final boolean USELETTERS = true;final boolean USENUMBERS = true;final int BEGININDEX = new Random().nextInt(32);final int ENDINDEX = BEGININDEX+32;this.csrfToken = RandomStringUtils.random(64, USELETTERS, USENUMBERS).substring(BEGININDEX, ENDINDEX);}
}

2.3 创建index.html (基于Webjars Bootstrap and jQuery)

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><meta name="description" content=""><meta name="author" content=""><link rel="icon" href="/oauth2/static/img/favicon.ico"><title>HIVESPLACE | Login</title><!-- Bootstrap core CSS --><link href="/oauth2/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet"><!-- Custom styles for this template --><link href="/oauth2/static/css/signin.css" rel="stylesheet"><link href="/oauth2/static/css/corporate.css" rel="stylesheet"></head><body class="text-center"><header class="display-none" id="loginWrap_header"><div class="corporate__header"><div class="header__wrapper"><div class="header__item"><nav class="top-bar"><span><div class="top-bar__holder"><a href="#" target="_blank"><span class="top-bar__txt">HIVESPLACE</span></a></div><div class="top-bar__holder"><a href="#" target="_blank"><span class="top-bar__txt">About HIVESPLACE</span></a></div><div class="top-bar__holder"></div></span></nav></div></div></div></header><div class="form-container row display-none" id="loginWrap_form"><div class="form-head-container my-auto"><div class="form-head"><img id="login-logo" class="mb-4" src="/oauth2/static/img/logoBee320x346.png" alt=""><h1 class="h3 mb-3 font-weight-normal">SSO Login</h1></div><div class="all-forms row"><form class="form-signin needs-validation" method="post" action="oauth-login" novalidate><div class="uname-pword"><p>请输入用户名及密码</p><input type="text" id="inputUsername" name="username" class="form-control login-uname" placeholder="Username" autocomplete="username" required><div class="form-group pass_show"> <input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" autocomplete="current-password" required><span class="ptxt" id="showPassword">Show</span></div> <button class="btn btn-lg btn-primary btn-block mt-5 btn-submit" id="autoSignIn" type="submit">登入</button></div></form><div style="clear:both;"></div></div></div></div><!-- Footer --><footer class="sticky-footer bg-white display-none" id="loginWrap_footer"><div class="container my-auto"><div class="copyright text-center my-auto"><span>版权 &copy; 2021 HIVESPLACE.com</span></div></div></footer><!-- End of Footer --><!-- Bootstrap core JavaScript================================================== --><!-- Placed at the end of the document so the pages load faster --><script src="/oauth2/webjars/jquery/jquery.min.js"></script><script src="/oauth2/webjars/bootstrap/js/bootstrap.min.js"></script><script src="/oauth2/static/js/signin.js"></script>
</body>
</html>
signin.js
// Example starter JavaScript for disabling form submissions if there are invalid fields(function() {'use strict';window.addEventListener('load', function() {// Fetch all the forms we want to apply custom Bootstrap validation styles tovar forms = document.getElementsByClassName('needs-validation');// Loop over them and prevent submissionvar validation = Array.prototype.filter.call(forms, function(form) {form.addEventListener('submit', function(event) {if (form.checkValidity() === false) {event.preventDefault();event.stopPropagation();}form.classList.add('was-validated');}, false);});}, false);//if(sessionStorage.autoLogin!=1){//console.log("session storage - username: "+sessionStorage.autoUsername);$("#loginWrap_header").removeClass("display-none");$("#loginWrap_form").removeClass("display-none");$("#loginWrap_footer").removeClass("display-none");/*}else{console.log("session storage - username: "+sessionStorage.autoUsername);$("#inputUsername").val(sessionStorage.autoUsername);$("#inputPassword").val(sessionStorage.autoPassword);$("#autoSignIn").click();}*/})();// jQuery for show password function
$('#showPassword').click(function(e){ /*jQuery 使用函数来设置内容语法:       $(selector).attr(attribute,function(index,oldvalue))*/$(this).text($(this).text() == "Show" ? "Hide" : "Show");/*jQuery 使用函数来设置属性/值语法:      $(selector).attr(attribute,function(index,oldvalue))*/$(this).prev().attr('type', function(index, attr){return attr == 'password' ? 'text' : 'password'; });
});// Stop redirect after validation pass & switch to SMS validation
var wrapWidth = $(".form-container").outerWidth();

总结

以上就是今天所讲的全部内容。

源代码

关注我并发表不少于10字评论可以获取本文源代码。

码农经典语录

Linus Torvalds
Talk is cheap, show me the code.

蜂窝码农

  • DRY Principle (Don’t Repeat Yourself) 是做技术的最大笑话, DRY Principle应该改成 DORY Principle (Do Repeat Yourself)才对
  • 没有中国参与的标准,不能称为世界标准

俗语
好读书、好记性不如烂笔头

参考链接

  • Mermaid https://mermaid-js.github.io/mermaid/#/
  • Apache Tomcat, which version to use: https://tomcat.apache.org/whichversion.html

基于oAuth2.0开发属于自己的SSO授权服务 - 授权码(Authourization Code)模式 (持续更新中。。。)相关推荐

  1. 20万数据 sql 快还是 java快?_基于SpringBoot2.0开发的,轻量级的,前后分离Java开发平台...

    项目说明 MintLeaf-Fast是一个基于SpringBoot2.0开发的,轻量级的,前后端分离的Java快速开发平台 开箱即用,节省开发时间,提升开发效率,能够快速开发项目并交付的接私活利器 支 ...

  2. 互联网API开放平台安全设计-基于OAuth2.0协议方式

    基于OAuth2.0协议方式 什么是OAuth OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站 ...

  3. 基于QtQuick2.0开发的诸多漂亮的界面例子(作为入门首选)

    # (持续更新)基于QtQuick2.0开发的诸多漂亮的界面例子(作为入门首选) ![驱动精灵主界面](http://7qn7mv.com1.z0.glb.clouddn.com/qtquickdri ...

  4. 基于JAVAWeb前端开发技术儿童教育网站计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVAWeb前端开发技术儿童教育网站计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVAWeb前端开发技术儿童教育网站计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: ...

  5. 基于若依开发的 Java EE 分布式微服务架构平台

    Admin Cloud 是一套企业级的多租户权限管理开发平台,基于 Admin Plus.iCRUD 和 若依.提供单体版和微服务版双版本.单体版(基于 Spring Boot) 和 微服务版(基于  ...

  6. 程序基于MATLAB yalmip 开发,做了一个简单的微网优化调度模型,模型中含有蓄电池储能、风电、光伏等发电单元,程序运行结果良好

    微网 优化调度 机组组合 YALMIP cplex 编程语言:MATLAB平台 主题:基于YALMIP 的微网优化调度模型 内容简介:程序基于MATLAB yalmip 开发,做了一个简单的微网优化调 ...

  7. 基于Android Studio开发的旅游记录与分享APP源码,Android旅游路线记录与分享APP源码

    GoTravelling 旅游路线记录与分享Android App--同享旅行 下载地址:基于Android Studio开发的旅游记录与分享APP源码 App介绍 目标用户 在寒暑假内希望结伴同游的 ...

  8. Go语言开发学习笔记(持续更新中)

    Go语言开发学习笔记(持续更新中) 仅供自我学习 更好的文档请选择下方 https://studygolang.com/pkgdoc https://www.topgoer.com/go%E5%9F% ...

  9. 【Vue全家桶+SSR+Koa2全栈开发】项目搭建过程 整合 学习目录(持续更新中)

    写在开头 大家好,这里是lionLoveVue,基础知识决定了编程思维,学如逆水行舟,不进则退.金三银四,为了面试也还在慢慢积累知识,Github上面可以直接查看所有前端知识点梳理,github传送门 ...

最新文章

  1. 十年AI学者影响力盘点:何恺明排名第一,华人学者呈正向流入
  2. intellij idea不显示git push按钮的解决办法
  3. python画数学函数_Python 绘制你想要的数学函数图形
  4. GPU并行计算OpenCL(2)——矩阵卷积
  5. Github html文件在线预览方法
  6. php 呼叫中心 源码,FreeSWITCH+Workerman+PHP 搭建呼叫中心
  7. td设置自动隐藏,hover事件触发全部显示,table列表不用担心信息太长导致界面不美观
  8. java单元测试模拟输入_java – 单元测试:在定义模拟行为后调用...
  9. CSS3魔法堂:说说Multi-column Layout
  10. java导出mysql数据表的结构生成word文档
  11. 组件分享之后端组件——用Go编写的IMAP4rev1库go-imap
  12. 站在巨人的肩膀上—英语
  13. win10重装应用商店
  14. linux该专接本还是工作_专升本还是继续工作?
  15. java newline_“\ n”和Environment.NewLine之间的区别
  16. Ozone数据探查服务Recon2.0设计
  17. 优化计算机 教学设计,信息技术优化教学设计
  18. 5个Libra协会成员加入,这家创业公司凭什么与Facebook 竞争?
  19. java xmpp协议_GitHub - zhengzhi530/xmpp: 基于Xmpp协议的即时通讯社交软件(客户端+服务端)...
  20. R语言与多元线性回归+逐步回归

热门文章

  1. 字符变量存放多个字符
  2. HBase 索引表结构
  3. 6-2 求子串*分数 20
  4. cmd命令行窗口运行py文件
  5. chown:修改用户的所属用户和所属组方法
  6. 继奇瑞小蚂蚁之后奇瑞新能源的又一力作,奇瑞无界Pro正式上市
  7. 山东大学软件学院2022年春操作系统期末考试
  8. scratch lenet(9): C语言实现tanh的计算
  9. QCustomPlot的使用教程(二)
  10. windows系统golang安装