OAuth2实现单点登录功能实战(附源码)

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> OAuth2实现单点登录功能实战(附源码)

点击上方“Java知音”,选择“置顶公众号”

技术文章第一时间送达!

作者:狂乱的贵公子 cnblogs.com/cjsblog/p/10548022.html

阅**(点击即可跳转阅读)**

1. 

**2. **

**3. **

**4. **

**5. **

1. 前言

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

OAuth2实现单点登录功能实战(附源码) OAuth2实现单点登录功能实战(附源码) OAuth2实现单点登录功能实战(附源码)

2. 准备

2.1. 单点登录

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

OAuth2实现单点登录功能实战(附源码)

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

OAuth2实现单点登录功能实战(附源码)

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

OAuth2实现单点登录功能实战(附源码)

重要的是理解:

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

    不是每次浏览器请求都要去SSO服务端去验证,只要浏览器和它所访问的服务端的会话有效它就可以正常访问

    2.2. OAuth2

    推荐以下几篇博客

    www.cnblogs.com/cjsblog/p/9174797.html www.cnblogs.com/cjsblog/p/9184173.html

    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"
        modelVersion4.0.0/modelVersion
        parent
            groupIdorg.springframework.boot/groupId
            artifactIdspring-boot-starter-parent/artifactId
            version2.1.3.RELEASE/version
            relativePath/ !-- lookup parent from repository --
        /parent
        groupIdcom.cjs.sso/groupId
        artifactIdoauth2-sso-auth-server/artifactId
        version0.0.1-SNAPSHOT/version
        nameoauth2-sso-auth-server/name
    
        properties
            java.version1.8/java.version
        /properties
    
        dependencies
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-data-jpa/artifactId
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-data-redis/artifactId
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-security/artifactId
            /dependency
            dependency
                groupIdorg.springframework.security.oauth.boot/groupId
                artifactIdspring-security-oauth2-autoconfigure/artifactId
                version2.1.3.RELEASE/version
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-thymeleaf/artifactId
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-web/artifactId
            /dependency
            dependency
                groupIdorg.springframework.session/groupId
                artifactIdspring-session-data-redis/artifactId
            /dependency
            dependency
                groupIdmysql/groupId
                artifactIdmysql-connector-java/artifactId
                scoperuntime/scope
            /dependency
            dependency
                groupIdorg.projectlombok/groupId
                artifactIdlombok/artifactId
                optionaltrue/optional
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-test/artifactId
                scopetest/scope
            /dependency
            dependency
                groupIdorg.springframework.security/groupId
                artifactIdspring-security-test/artifactId
                scopetest/scope
            /dependency
    
            dependency
                groupIdorg.apache.commons/groupId
                artifactIdcommons-lang3/artifactId
                version3.8.1/version
            /dependency
            dependency
                groupIdcom.alibaba/groupId
                artifactIdfastjson/artifactId
                version1.2.56/version
            /dependency
    
        /dependencies
    
        build
            plugins
                plugin
                    groupIdorg.springframework.boot/groupId
                    artifactIdspring-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: 6379
    server:
      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;
        }
    
    }
    

    说明:

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

    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
    @EnableWebSecurity
    public 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"
        titleEla 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"
                            labelUsername/label
                            input type="text" class="form-control" name="username" placeholder="Username"
                        /div
                        div class="form-group"
                            labelPassword/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. 定义客户端

    OAuth2实现单点登录功能实战(附源码) OAuth2实现单点登录功能实战(附源码)

    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
    @Service
    public 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);
            }
            ListSysPermission permissionList = permissionService.findByUserId(sysUser.getId());
            ListSimpleGrantedAuthority 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. 验证

    OAuth2实现单点登录功能实战(附源码)

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

    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"
        modelVersion4.0.0/modelVersion
        parent
            groupIdorg.springframework.boot/groupId
            artifactIdspring-boot-starter-parent/artifactId
            version2.1.3.RELEASE/version
            relativePath/ !-- lookup parent from repository --
        /parent
        groupIdcom.cjs.sso/groupId
        artifactIdoauth2-sso-client-member/artifactId
        version0.0.1-SNAPSHOT/version
        nameoauth2-sso-client-member/name
        descriptionDemo project for Spring Boot/description
    
        properties
            java.version1.8/java.version
        /properties
    
        dependencies
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-data-jpa/artifactId
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-oauth2-client/artifactId
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-security/artifactId
            /dependency
            dependency
                groupIdorg.springframework.security.oauth.boot/groupId
                artifactIdspring-security-oauth2-autoconfigure/artifactId
                version2.1.3.RELEASE/version
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-thymeleaf/artifactId
            /dependency
            dependency
                groupIdorg.thymeleaf.extras/groupId
                artifactIdthymeleaf-extras-springsecurity5/artifactId
                version3.0.4.RELEASE/version
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-web/artifactId
            /dependency
    
            dependency
                groupIdcom.h2database/groupId
                artifactIdh2/artifactId
                scoperuntime/scope
            /dependency
            dependency
                groupIdorg.projectlombok/groupId
                artifactIdlombok/artifactId
                optionaltrue/optional
            /dependency
            dependency
                groupIdorg.springframework.boot/groupId
                artifactIdspring-boot-starter-test/artifactId
                scopetest/scope
            /dependency
            dependency
                groupIdorg.springframework.security/groupId
                artifactIdspring-security-test/artifactId
                scopetest/scope
            /dependency
        /dependencies
    
        build
            plugins
                plugin
                    groupIdorg.springframework.boot/groupId
                    artifactIdspring-boot-maven-plugin/artifactId
                /plugin
            /plugins
        /build
    
    /project
    

    5.2. application.yml

    
    server:
      port: 8082
      servlet:
        context-path: /memberSystem
    security:
      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
    
    OAuth2实现单点登录功能实战(附源码)

    这里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();
            }
        }
    }
    

    说明:

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

    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就不是那么容易,关于这一点,在官网上也有提到:

    OAuth2实现单点登录功能实战(附源码)

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

    6. 工程结构

    OAuth2实现单点登录功能实战(附源码)

    附上源码:

    https://github.com/chengjiansheng/cjs-oauth2-sso-demo.git

    7. 参考

    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

    8. 文档

    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

    觉得不错?欢迎转发分享给更多人

    OAuth2实现单点登录功能实战(附源码)

    原文始发于微信公众号(Java知音):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> OAuth2实现单点登录功能实战(附源码)


     上一篇
    后端开发实践——Spring Boot项目模板 后端开发实践——Spring Boot项目模板
    点击上方“Java知音”,选择“置顶公众号” 技术文章第一时间送达! 作者:无知者云 https://www.cnblogs.com/davenkin/ 推荐阅**读(点击即可跳转阅读)** 1.  **2. ** **3.
    下一篇 
    SpringBoot集成Elasticsearch实战 SpringBoot集成Elasticsearch实战
    点击上方“Java知音”,选择“置顶公众号” 技术文章第一时间送达! 作者:废物大师兄  cnblogs.com/cjsblog/p/9756978.html 推荐阅**读(点击即可跳转阅读)** 1.  **2. ** *