<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          單點登錄(SSO),一看就會,一做就錯!

          共 42537字,需瀏覽 86分鐘

           ·

          2021-07-12 17:47


          技術(shù)這東西吧,看別人寫的好像很簡單似的,到自己去寫的時候就各種問題,“一看就會,一做就錯”。


          圖片來自 Pexels


          網(wǎng)上關(guān)于實現(xiàn) SSO 的文章一大堆,但是當(dāng)你真的照著寫的時候就會發(fā)現(xiàn)根本不是那么回事兒,簡直讓人抓狂,尤其是對于我這樣的菜鳥。


          幾經(jīng)曲折,終于搞定了,決定記錄下來,以便后續(xù)查看。先來看一下效果:


          準(zhǔn)備


          ①單點登錄


          最常見的例子是,我們打開淘寶 APP,首頁就會有天貓、聚劃算等服務(wù)的鏈接,當(dāng)你點擊以后就直接跳過去了,并沒有讓你再登錄一次。

          下面這個圖是我在網(wǎng)上找的,我覺得畫得比較明白:
          可惜有點兒不清晰,于是我又畫了個簡版的:

          重要的是理解:

          • SSO 服務(wù)端和 SSO 客戶端直接是通過授權(quán)以后發(fā)放 Token 的形式來訪問受保護(hù)的資源。

          • 相對于瀏覽器來說,業(yè)務(wù)系統(tǒng)是服務(wù)端,相對于 SSO 服務(wù)端來說,業(yè)務(wù)系統(tǒng)是客戶端。

          • 瀏覽器和業(yè)務(wù)系統(tǒng)之間通過會話正常訪問。

          • 不是每次瀏覽器請求都要去 SSO 服務(wù)端去驗證,只要瀏覽器和它所訪問的服務(wù)端的會話有效它就可以正常訪問。


          利用 OAuth2 實現(xiàn)單點登錄


          接下來,只講跟本例相關(guān)的一些配置,不講原理,不講為什么。


          眾所周知,在 OAuth2 在有授權(quán)服務(wù)器、資源服務(wù)器、客戶端這樣幾個角色,當(dāng)我們用它來實現(xiàn) SSO 的時候是不需要資源服務(wù)器這個角色的,有授權(quán)服務(wù)器和客戶端就夠了。


          授權(quán)服務(wù)器當(dāng)然是用來做認(rèn)證的,客戶端就是各個應(yīng)用系統(tǒng),我們只需要登錄成功后拿到用戶信息以及用戶所擁有的權(quán)限即可。

          之前我一直認(rèn)為把那些需要權(quán)限控制的資源放到資源服務(wù)器里保護(hù)起來就可以實現(xiàn)權(quán)限控制,其實是我想錯了,權(quán)限控制還得通過 Spring Security 或者自定義攔截器來做。


          ①Spring Security 、OAuth2、JWT、SSO


          在本例中,一定要分清楚這幾個的作用:


          首先,SSO 是一種思想,或者說是一種解決方案,是抽象的,我們要做的就是按照它的這種思想去實現(xiàn)它。

          其次,OAuth2 是用來允許用戶授權(quán)第三方應(yīng)用訪問他在另一個服務(wù)器上的資源的一種協(xié)議,它不是用來做單點登錄的,但我們可以利用它來實現(xiàn)單點登錄。


          在本例實現(xiàn) SSO 的過程中,受保護(hù)的資源就是用戶的信息(包括,用戶的基本信息,以及用戶所具有的權(quán)限)。


          而我們想要訪問這這一資源就需要用戶登錄并授權(quán),OAuth2 服務(wù)端負(fù)責(zé)令牌的發(fā)放等操作,這令牌的生成我們采用 JWT,也就是說 JWT 是用來承載用戶的 Access_Token 的。


          最后,Spring Security 是用于安全訪問的,這里我們我們用來做訪問權(quán)限控制。

          認(rèn)證服務(wù)器配置


          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。


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

          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。

          • 客戶端以及登錄用戶這些配置存儲在數(shù)據(jù)庫,為了減少數(shù)據(jù)庫的查詢次數(shù),可以從數(shù)據(jù)庫讀出來以后再放到內(nèi)存中。


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

          }

          自定義登錄頁面(一般來講都是要自定義的):
          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";
              }

          }

          自定義登錄頁面的時候,只需要準(zhǔn)備一個登錄頁面,然后寫個 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>

          定義客戶端,如下圖:


          加載用戶,登錄賬戶:
          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即可不必擴(kuò)展
           * @author ChengJianSheng
           * @date 2019-02-11
           */

          @Data
          public class MyUser extends User {

              private Integer departmentId;   //  舉個例子,部門ID

              private String mobile;  //  舉個例子,假設(shè)我們想增加一個字段,這里我們增加一個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);
                  }
                  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;
              }
          }

          驗證:

          當(dāng)我們看到這個界面的時候,表示認(rèn)證服務(wù)器配置完成?! ?/span>

          兩個客戶端


          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>

          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

          這里 context-path 不要設(shè)成 /,不然重定向獲取 code 的時候回被攔截。


          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。

          • 權(quán)限控制這里采用 Spring Security 方法級別的訪問控制,結(jié)合 Thymeleaf 可以很容易做權(quán)限控制。

          • 順便多提一句,如果是前后端分離的話,前端需求加載用戶的權(quán)限,然后判斷應(yīng)該顯示那些按鈕那些菜單。


          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";
              }
          }


          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

          關(guān)于退出:退出就是清空用于與 SSO 客戶端建立的所有的會話,簡單的來說就是使所有端點的 Session 失效,如果想做得更好的話可以令 Token 失效,但是由于我們用的 JWT,故而撤銷 Token 就不是那么容易,關(guān)于這一點,在官網(wǎng)上也有提到:

          本例中采用的方式是在退出的時候先退出業(yè)務(wù)服務(wù)器,成功以后再回調(diào)認(rèn)證服務(wù)器,但是這樣有一個問題,就是需要主動依次調(diào)用各個業(yè)務(wù)服務(wù)器的 logout。

          工程結(jié)構(gòu)


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

          演示


          作者:廢物大師兄

          出處:cnblogs.com/cjsblog/p/10548022.html


          推薦閱讀:

          世界的真實格局分析,地球人類社會底層運行原理

          企業(yè)數(shù)字化轉(zhuǎn)型與運營策略(120頁PPT)

          企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案

          論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

          企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

          【中臺實踐】華為大數(shù)據(jù)中臺架構(gòu)分享.pdf

          華為的數(shù)字化轉(zhuǎn)型方法論

          華為如何實施數(shù)字化轉(zhuǎn)型(附PPT)

          超詳細(xì)280頁Docker實戰(zhàn)文檔!開放下載

          華為大數(shù)據(jù)解決方案(PPT)

          瀏覽 38
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  18禁免费观看网站 | 国产肏屄青青肏屄视频 | 成人一区二区三区四区五区六区七区 | 五月婷婷六月激情 | 我爱大香蕉欧美高清无 |