天天看點

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

  • 1. 前言
  • 2. 準備
  • 3. 利用OAuth2實作單點登入
  • 4. 認證伺服器配置
  • 5. 兩個用戶端
  • 6. 工程結構
  • 7. 示範
  • 8. 參考
  • 9. 文檔
  • 《Java 2019 超神之路》
  • 《Dubbo 實作原理與源碼解析 —— 精品合集》
  • 《Spring 實作原理與源碼解析 —— 精品合集》
  • 《MyBatis 實作原理與源碼解析 —— 精品合集》
  • 《Spring MVC 實作原理與源碼解析 —— 精品合集》
  • 《Spring Boot 實作原理與源碼解析 —— 精品合集》
  • 《資料庫實體設計合集》
  • 《Java 面試題 —— 精品合集》
  • 《Java 學習指南 —— 精品合集》

1. 前言

技術這東西吧,看别人寫的好像很簡單似的,到自己去寫的時候就各種問題,“一看就會,一做就錯”。網上關于實作SSO的文章一大堆,但是當你真的照着寫的時候就會發現根本不是那麼回事兒,簡直讓人抓狂,尤其是對于我這樣的菜鳥。幾經曲折,終于搞定了,決定記錄下來,以便後續檢視。先來看一下效果

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)
java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)
java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

2. 準備

2.1. 單點登入

最常見的例子是,我們打開淘寶APP,首頁就會有天貓、聚劃算等服務的連結,當你點選以後就直接跳過去了,并沒有讓你再登入一次

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

下面這個圖是我再網上找的,我覺得畫得比較明白:

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

可惜有點兒不清晰,于是我又畫了個簡版的:

重要的是了解:

  • SSO服務端和SSO用戶端直接是通過授權以後發放Token的形式來通路受保護的資源
  • 相對于浏覽器來說,業務系統是服務端,相對于SSO服務端來說,業務系統是用戶端
  • 浏覽器和業務系統之間通過會話正常通路
  • 不是每次浏覽器請求都要去SSO服務端去驗證,隻要浏覽器和它所通路的服務端的會話有效它就可以正常通路
java oauth2登入以及權限_OAuth2 實作單點登入 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: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
publicclass 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() {
        returnnew 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
@EnableWebSecurity
publicclass 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() {
        returnnew 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
publicclass 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}" target="_blank" rel="external nofollow" >
    <link type="text/css" rel="stylesheet" th:href="@{/assets/bootstrap-4.3.1-dist/css/bootstrap.min.css}" target="_blank" rel="external nofollow" >
    <link type="text/css" rel="stylesheet" th:href="@{/assets/css/font-awesome.min.css}" target="_blank" rel="external nofollow" >
    <link type="text/css" rel="stylesheet" th:href="@{/assets/css/style.css}" target="_blank" rel="external nofollow" >

</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="#" target="_blank" rel="external nofollow" >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. 定義用戶端

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)
java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

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
publicclass 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
publicclass 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);
            thrownew 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. 驗證

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

當我們看到這個界面的時候,表示認證伺服器配置完成

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: /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
           
java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

這裡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
publicclass 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")
publicclass 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就不是那麼容易,關于這一點,在官網上也有提到:

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

本例中采用的方式是在退出的時候先退出業務伺服器,成功以後再回調認證伺服器,但是這樣有一個問題,就是需要主動依次調用各個業務伺服器的logout

6. 工程結構

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

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

7. 示範

java oauth2登入以及權限_OAuth2 實作單點登入 SSO(流程圖 + 代碼)

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

繼續閱讀