SpringBoot OAuth2 JWT实现单点登录SSO完整教程,竟如此简单优雅!

作者:狂乱的贵公子

来源:https://www.cnblogs.com/cjsblog/p/10548022.html

1.前言

技术这东西吧,看别人写的好像很简单似的,到自己去写的时候就各种问题,“一看就会,一做就错”。网上关于实现SSO的文章一大堆,但是当你真的照着写的时候就会发现根本不是那么回事儿,简直让人抓狂,尤其是对于我这样的菜鸟。几经曲折,终于搞定了,决定记录下来,以便后续查看。先来看一下效果

2.准备

2.1. 单点登录

最常见的例子是,我们打开淘宝APP,首页就会有天猫、聚划算等服务的链接,当你点击以后就直接跳过去了,并没有让你再登录一次

下面这个图是我再网上找的,我觉得画得比较明白:

可惜有点儿不清晰,于是我又画了个简版的:

重要的是理解:

  • SSO服务端和SSO客户端直接是通过授权以后发放Token的形式来访问受保护的资源
  • 相对于浏览器来说,业务系统是服务端,相对于SSO服务端来说,业务系统是客户端
  • 浏览器和业务系统之间通过会话正常访问
  • 不是每次浏览器请求都要去SSO服务端去验证,只要浏览器和它所访问的服务端的会话有效它就可以正常访问

2.2. OAuth2

推荐以下几篇博客

《OAuth 2.0》

《Spring Security对OAuth2的支持》

3.利用OAuth2实现单点登录

接下来,只讲跟本例相关的一些配置,不讲原理,不讲为什么

众所周知,在OAuth2在有授权服务器、资源服务器、客户端这样几个角色,当我们用它来实现SSO的时候是不需要资源服务器这个角色的,有授权服务器和客户端就够了。

授权服务器当然是用来做认证的,客户端就是各个应用系统,我们只需要登录成功后拿到用户信息以及用户所拥有的权限即可

之前我一直认为把那些需要权限控制的资源放到资源服务器里保护起来就可以实现权限控制,其实是我想错了,权限控制还得通过Spring Security或者自定义拦截器来做

3.1. Spring Security 、OAuth2、JWT、SSO

在本例中,一定要分清楚这几个的作用

首先,SSO是一种思想,或者说是一种解决方案,是抽象的,我们要做的就是按照它的这种思想去实现它

其次,OAuth2是用来允许用户授权第三方应用访问他在另一个服务器上的资源的一种协议,它不是用来做单点登录的,但我们可以利用它来实现单点登录。在本例实现SSO的过程中,受保护的资源就是用户的信息(包括,用户的基本信息,以及用户所具有的权限),而我们想要访问这这一资源就需要用户登录并授权,OAuth2服务端负责令牌的发放等操作,这令牌的生成我们采用JWT,也就是说JWT是用来承载用户的Access_Token的

最后,Spring Security是用于安全访问的,这里我们我们用来做访问权限控制

4.认证服务器配置

4.1. Maven依赖

<?xml version='1.0' encoding='UTF-8'?>
<project xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
         xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd'>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cjs.sso</groupId>
    <artifactId>oauth2-sso-auth-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>oauth2-sso-auth-server</name>

<properties>
        <java.version>1.8</java.version>
    </properties>

<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-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.1.3.RELEASE</version>
        </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.session</groupId>
            <artifactId>spring-session-data-redis</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.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>

</dependencies>

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

这里面最重要的依赖是:spring-security-oauth2-autoconfigure

4.2. application.yml

spring:  datasource:    url: jdbc:mysql://localhost:3306/permission    username: root    password: 123456    driver-class-name: com.mysql.jdbc.Driver  jpa:    show-sql: true  session:    store-type: redis  redis:    host: 127.0.0.1    password: 123456    port: 6379server:  port: 8080

4.3. AuthorizationServerConfig(重要)

package com.cjs.sso.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.token.DefaultToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.sql.DataSource;

/**
 * @author ChengJianSheng
 * @date 2019-02-11
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

@Autowired
    private DataSource dataSource;

@Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
        security.tokenKeyAccess('isAuthenticated()');
    }

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.accessTokenConverter(jwtAccessTokenConverter());
        endpoints.tokenStore(jwtTokenStore());
//        endpoints.tokenServices(defaultTokenServices());
    }

/*@Primary
    @Bean
    public DefaultTokenServices defaultTokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(jwtTokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }*/

@Bean
    public JwtTokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

@Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey('cjs');   //  Sets the JWT signing key
        return jwtAccessTokenConverter;
    }

}

说明:

  1. 别忘了**@EnableAuthorizationServer**
  2. Token存储采用的是JWT
  3. 客户端以及登录用户这些配置存储在数据库,为了减少数据库的查询次数,可以从数据库读出来以后再放到内存中

4.4. WebSecurityConfig(重要)

package com.cjs.sso.config;

import com.cjs.sso.service.MyUserDetailsService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.builders.WebSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;

/** * @author ChengJianSheng * @date 2019-02-11 */@Configuration@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired    private MyUserDetailsService userDetailsService;

    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());    }

    @Override    public void configure(WebSecurity web) throws Exception {        web.ignoring().antMatchers('/assets/**', '/css/**', '/images/**');    }

    @Override    protected void configure(HttpSecurity http) throws Exception {        http.formLogin()                .loginPage('/login')                .and()                .authorizeRequests()                .antMatchers('/login').permitAll()                .anyRequest()                .authenticated()                .and().csrf().disable().cors();    }

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

}

4.5. 自定义登录页面(一般来讲都是要自定义的)

package com.cjs.sso.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author ChengJianSheng
 * @date 2019-02-12
 */
@Controller
public class LoginController {

@GetMapping('/login')
    public String login() {
        return 'login';
    }

@GetMapping('/')
    public String index() {
        return 'index';
    }

}

自定义登录页面的时候,只需要准备一个登录页面,然后写个Controller令其可以访问到即可,登录页面表单提交的时候method一定要是post,最重要的时候action要跟访问登录页面的url一样

千万记住了,访问登录页面的时候是GET请求,表单提交的时候是POST请求,其它的就不用管了

<!DOCTYPE html><html xmlns:th='http://www.thymeleaf.org'><head>    <meta charset='utf-8'>    <meta http-equiv='X-UA-Compatible' content='IE=edge'>    <title>Ela Admin - HTML5 Admin Template</title>    <meta name='description' content='Ela Admin - HTML5 Admin Template'>    <meta name='viewport' content='width=device-width, initial-scale=1'>

    <link type='text/css' rel='stylesheet' th:href='@{/assets/css/normalize.css}'>    <link type='text/css' rel='stylesheet' th:href='@{/assets/bootstrap-4.3.1-dist/css/bootstrap.min.css}'>    <link type='text/css' rel='stylesheet' th:href='@{/assets/css/font-awesome.min.css}'>    <link type='text/css' rel='stylesheet' th:href='@{/assets/css/style.css}'>

</head><body class='bg-dark'>

<div class='sufee-login d-flex align-content-center flex-wrap'>    <div class='container'>        <div class='login-content'>            <div class='login-logo'>                <h1 style='color: #57bf95;'>欢迎来到王者荣耀</h1>            </div>            <div class='login-form'>                <form th:action='@{/login}' method='post'>                    <div class='form-group'>                        <label>Username</label>                        <input type='text' class='form-control' name='username' placeholder='Username'>                    </div>                    <div class='form-group'>                        <label>Password</label>                        <input type='password' class='form-control' name='password' placeholder='Password'>                    </div>                    <div class='checkbox'>                        <label>                            <input type='checkbox'> Remember Me                        </label>                        <label class='pull-right'>                            <a href='#'>Forgotten Password?</a>                        </label>                    </div>                    <button type='submit' class='btn btn-success btn-flat m-b-30 m-t-30' style='font-size: 18px;'>登录</button>                </form>            </div>        </div>    </div></div>

<script type='text/javascript' th:src='@{/assets/js/jquery-2.1.4.min.js}'></script><script type='text/javascript' th:src='@{/assets/bootstrap-4.3.1-dist/js/bootstrap.min.js}'></script><script type='text/javascript' th:src='@{/assets/js/main.js}'></script>

</body></html>

4.6. 定义客户端

4.7. 加载用户

登录账户

package com.cjs.sso.domain;

import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;

/**
 * 大部分时候直接用User即可不必扩展
 * @author ChengJianSheng
 * @date 2019-02-11
 */
@Data
public class MyUser extends User {

private Integer departmentId;   //  举个例子,部门ID

private String mobile;  //  举个例子,假设我们想增加一个字段,这里我们增加一个mobile表示手机号

public MyUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
    }

public MyUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
    }
}

加载登录账户

package com.cjs.sso.service;

import com.alibaba.fastjson.JSON;import com.cjs.sso.domain.MyUser;import com.cjs.sso.entity.SysPermission;import com.cjs.sso.entity.SysUser;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.stereotype.Service;import org.springframework.util.CollectionUtils;

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

/** * @author ChengJianSheng * @date 2019-02-11 */@Slf4j@Servicepublic class MyUserDetailsService implements UserDetailsService {

    @Autowired    private PasswordEncoder passwordEncoder;

    @Autowired    private UserService userService;

    @Autowired    private PermissionService permissionService;

    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        SysUser sysUser = userService.getByUsername(username);        if (null == sysUser) {            log.warn('用户{}不存在', username);            throw new UsernameNotFoundException(username);        }        List<SysPermission> permissionList = permissionService.findByUserId(sysUser.getId());        List<SimpleGrantedAuthority> authorityList = new ArrayList<>();        if (!CollectionUtils.isEmpty(permissionList)) {            for (SysPermission sysPermission : permissionList) {                authorityList.add(new SimpleGrantedAuthority(sysPermission.getCode()));            }        }

        MyUser myUser = new MyUser(sysUser.getUsername(), passwordEncoder.encode(sysUser.getPassword()), authorityList);

        log.info('登录成功!用户: {}', JSON.toJSONString(myUser));

        return myUser;    }}

4.8. 验证

img

当我们看到这个界面的时候,表示认证服务器配置完成

5.两个客户端

5.1. Maven依赖

<?xml version='1.0' encoding='UTF-8'?>
<project xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
         xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd'>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cjs.sso</groupId>
    <artifactId>oauth2-sso-client-member</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>oauth2-sso-client-member</name>
    <description>Demo project for Spring Boot</description>

<properties>
        <java.version>1.8</java.version>
    </properties>

<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-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</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>
    </dependencies>

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

5.2. application.yml

server:  port: 8082  servlet:    context-path: /memberSystemsecurity:  oauth2:    client:      client-id: UserManagement      client-secret: user123      access-token-uri: http://localhost:8080/oauth/token      user-authorization-uri: http://localhost:8080/oauth/authorize    resource:      jwt:        key-uri: http://localhost:8080/oauth/token_key
img

这里context-path不要设成/,不然重定向获取code的时候回被拦截

5.3. WebSecurityConfig

package com.cjs.example.config;

import com.cjs.example.util.EnvironmentUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author ChengJianSheng
 * @date 2019-03-03
 */
@EnableOAuth2Sso
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
    private EnvironmentUtils environmentUtils;

@Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers('/bootstrap/**');
    }

@Override
    protected void configure(HttpSecurity http) throws Exception {
        if ('local'.equals(environmentUtils.getActiveProfile())) {
            http.authorizeRequests().anyRequest().permitAll();
        }else {
            http.logout().logoutSuccessUrl('http://localhost:8080/logout')
                    .and()
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .csrf().disable();
        }
    }
}

说明:

  1. 最重要的注解是@EnableOAuth2Sso
  2. 权限控制这里采用Spring Security方法级别的访问控制,结合Thymeleaf可以很容易做权限控制
  3. 顺便多提一句,如果是前后端分离的话,前端需求加载用户的权限,然后判断应该显示那些按钮那些菜单

5.4. MemberController

package com.cjs.example.controller;

import org.springframework.security.access.prepost.PreAuthorize;import org.springframework.security.core.Authentication;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;

import java.security.Principal;

/** * @author ChengJianSheng * @date 2019-03-03 */@Controller@RequestMapping('/member')public class MemberController {

    @GetMapping('/list')    public String list() {

        return 'member/list';    }

    @GetMapping('/info')    @ResponseBody    public Principal info(Principal principal) {        return principal;    }

    @GetMapping('/me')    @ResponseBody    public Authentication me(Authentication authentication) {        return authentication;    }

    @PreAuthorize('hasAuthority('member:save')')    @ResponseBody    @PostMapping('/add')    public String add() {

        return 'add';    }

    @PreAuthorize('hasAuthority('member:detail')')    @ResponseBody    @GetMapping('/detail')    public String detail() {        return 'detail';    }}

5.5. Order项目跟它是一样的

server:
  port: 8083
  servlet:
    context-path: /orderSystem
security:
  oauth2:
    client:
      client-id: OrderManagement
      client-secret: order123
      access-token-uri: http://localhost:8080/oauth/token
      user-authorization-uri: http://localhost:8080/oauth/authorize
    resource:
      jwt:
        key-uri: http://localhost:8080/oauth/token_key

5.6. 关于退出

退出就是清空用于与SSO客户端建立的所有的会话,简单的来说就是使所有端点的Session失效,如果想做得更好的话可以令Token失效,但是由于我们用的JWT,故而撤销Token就不是那么容易,关于这一点,在官网上也有提到:

本例中采用的方式是在退出的时候先退出业务服务器,成功以后再回调认证服务器,但是这样有一个问题,就是需要主动依次调用各个业务服务器的logout

6.工程结构

附上源码:https://github.com/chengjiansheng/cjs-oauth2-sso-demo.git

7. 演示

8.参考

https://www.cnblogs.com/cjsblog/p/9174797.html

https://www.cnblogs.com/cjsblog/p/9184173.html

https://www.cnblogs.com/cjsblog/p/9230990.html

https://www.cnblogs.com/cjsblog/p/9277677.html

https://blog.csdn.net/fooelliot/article/details/83617941

http://blog.leapoahead.com/2015/09/07/user-authentication-with-jwt/

https://www.cnblogs.com/lihaoyang/p/8581077.html

https://www.cnblogs.com/charlypage/p/9383420.html

http://www.360doc.com/content/18/0306/17/16915_734789216.shtml

https://blog.csdn.net/chenjianandiyi/article/details/78604376

https://www.baeldung.com/spring-security-oauth-jwt

https://www.baeldung.com/spring-security-oauth-revoke-tokens

https://www.reinforce.cn/t/630.html

9.文档

https://projects.spring.io/spring-security-oauth/docs/oauth2.html

https://docs.spring.io/spring-security-oauth2-boot/docs/2.1.3.RELEASE/reference/htmlsingle/

https://docs.spring.io/spring-security-oauth2-boot/docs/2.1.3.RELEASE/

https://docs.spring.io/spring-security-oauth2-boot/docs/

https://docs.spring.io/spring-boot/docs/2.1.3.RELEASE/

https://docs.spring.io/spring-boot/docs/

https://docs.spring.io/spring-framework/docs/

https://docs.spring.io/spring-framework/docs/5.1.4.RELEASE/

https://spring.io/guides/tutorials/spring-boot-oauth2/

https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#core-services-password-encoding

https://spring.io/projects/spring-cloud-security

https://cloud.spring.io/spring-cloud-security/single/spring-cloud-security.html

https://docs.spring.io/spring-session/docs/current/reference/html5/guides/java-security.html

https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-redis.html#boot-spring-configuration

点击阅读全文前往微服务电商教程
(0)

相关推荐

  • IDEA中SpringBoot搭建子父工程demo

    IDEA中SpringBoot搭建子父工程demo

  • SpringCloud之Zuul

    [前面的话]书接上文,前面已经讲过了SpringCloud的注册中心Eureka.Ribbon和Feign等等,如果有不清楚的也可以去看看我的微服务系列文章.这篇文章我要说的是微服务中的网关. 壹.Z ...

  • OAuth2实现单点登录SSO

    OAuth2实现单点登录SSO

  • OAuth2、CAS单点登录

    一.Oauth 是一个关于授权(authorization)的开网络标准(规范) OAuth2: 解决的是不同的企业之间的登录,本质是授权,如论坛与QQ 要能访问各种资源重点是要获取令牌(token) ...

  • 基于JWT和CAS的SSO单点登录方案

    单点登录是一种比较流行的服务于企业业务整合的一种解决方案.单点登录(SSO:Single Sign On)的意思是:在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.比如我们登录淘 ...

  • spring+springmvc+Interceptor+jwt+redis实现sso单点登录

    在分布式环境中,如何支持PC.APP(ios.android)等多端的会话共享,这也是所有公司都需要的解决方案,用传统的session方式来解决,我想已经out了,我们是否可以找一个通用的方案,比如用 ...

  • 用PHP实现SSO单点登录系统接入功能与分析

    SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制 ...

  • 八幅漫画理解使用 JWT 设计的单点登录系统

    阅读本文大概需要 6 分钟. JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息. 让我们来假想一下一个场景.在A用户关注了B用 ...

  • SpringCloud SpringBoot OAuth2 Spring Security Redi...

    来自:CSDN,作者:myCat 链接:https://blog.csdn.net/WYA1993/article/details/85050120 开发环境: Windows10 Intellij ...

  • 单点登录简介

    单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录. 当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对 ...

  • 单点登录的三种实现方式

    前言 实现方式一:父域 Cookie 实现方式二:认证中心 实现方式三:LocalStorage 跨域 补充:域名分级 前言 在 B/S 系统中,登录功能通常都是基于 Cookie 来实现的.当用户登 ...