最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot SSO輕松實(shí)現(xiàn)(附demo)

 更新時(shí)間:2021年01月29日 09:55:28   作者:何裕華  
這篇文章主要介紹了SpringBoot SSO輕松實(shí)現(xiàn)(附demo),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

網(wǎng)上SSO的框架很多,此篇文章使用的是自寫的SSO來實(shí)現(xiàn)簡(jiǎn)單的登錄授權(quán)功能,目的在于擴(kuò)展性,權(quán)限這方面,自寫擴(kuò)展性會(huì)好點(diǎn)。

提示:以下是本篇文章正文內(nèi)容,下面案例可供參考

一、技術(shù)介紹

1.SSO是什么?

單點(diǎn)登錄(SingleSignOn,SSO),就是通過用戶的一次性鑒別登錄。當(dāng)用戶在身份認(rèn)證服務(wù)器上登錄一次以后,即可獲得訪問單點(diǎn)登錄系統(tǒng)中其他關(guān)聯(lián)系統(tǒng)和應(yīng)用軟件的權(quán)限,同時(shí)這種實(shí)現(xiàn)是不需要管理員對(duì)用戶的登錄狀態(tài)或其他信息進(jìn)行修改的,這意味著在多個(gè)應(yīng)用系統(tǒng)中,用戶只需一次登錄就可以訪問所有相互信任的應(yīng)用系統(tǒng)。這種方式減少了由登錄產(chǎn)生的時(shí)間消耗,輔助了用戶管理,是目前比較流行的。

二、使用步驟

1.引入maven庫(kù)

代碼如下(示例):

 <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.4.1</version>
     <relativePath/>
  </parent>
   <dependencies>
    <dependencies>
    <dependency>
      <artifactId>hyh-boot-starter-redis</artifactId>
      <groupId>com.hyh.redis</groupId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>

2.具體使用示例

ILogin接口:

package com.hyh.sso;

import com.hyh.sso.po.LoginResult;

/**
 * 登錄接口
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 17:14
 */
public interface ILogin {

  /**
   * 登錄
   *
   * @param account   用戶名
   * @param password  密碼
   * @param callbackUrl 用戶驗(yàn)證回調(diào)URL
   * @return
   */
  LoginResult login(String account, String password, String callbackUrl);
}

登錄狀態(tài)枚舉:

package com.hyh.sso;

/**
 * 登錄狀態(tài)枚舉
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 16:59
 */
public enum LoginStatus {

  SUCCESS(1, "登錄成功"), ING(0, "登錄中"), FAIL(-1, "登錄失敗"),
  ERROR(-2, "登錄異常"), CALLBACK_ERROR(-3, "登錄回調(diào)異常"), ACCOUNT_LOCK(-4, "賬戶被鎖定"),
  EXPIRE(-5,"登錄用戶已過期");
  /**
   * 登錄狀態(tài)碼
   */
  private int code;
  /**
   * 登錄狀態(tài)消息
   */
  private String message;


  private LoginStatus(int code, String message) {
    this.code = code;
    this.message = message;
  }


  public int getCode() {
    return code;
  }

  public void setCode(int code) {
    this.code = code;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }
  }

登錄類型枚舉:

package com.hyh.sso;

/**
 * 登錄類型
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 17:16
 */
public enum LoginTypes {

  /**
   * 登入
   */
  IN,
  /**
   * 登出
   */
  OUT;
}

登錄常規(guī)接口:

package com.hyh.sso;

package com.hyh.sso.service;

import com.hyh.sso.ILogin;

/**
 * 常規(guī)登錄接口
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 17:54
 */
public interface LoginService extends ILogin {

}

登錄接口實(shí)現(xiàn):

package com.hyh.sso.service.impl;

import com.alibaba.fastjson.JSON;
import com.hyh.sso.LoginStatus;
import com.hyh.sso.po.LoginResult;
import com.hyh.sso.po.LoginUser;
import com.hyh.sso.service.LoginService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * 登錄接口實(shí)現(xiàn)
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 17:56
 */
@Service
public class LoginServiceImpl implements LoginService {

  private static final Logger LOG = LoggerFactory.getLogger(LoginServiceImpl.class);

  /**
   * rest接口請(qǐng)求模板
   */
  private static RestTemplate restTemplate = new RestTemplate();


  @Override
  public LoginResult login(String account, String password, String callbackUrl) {
    LoginResult loginResult = null;
    try {
      HttpHeaders headers = new HttpHeaders();
      //設(shè)置請(qǐng)求媒體數(shù)據(jù)類型
      headers.setContentType(MediaType.APPLICATION_JSON);
      //設(shè)置返回媒體數(shù)據(jù)類型
      headers.add("Accept", MediaType.APPLICATION_JSON.toString());
      HttpEntity<String> formEntity = new HttpEntity<String>(JSON.toJSONString(new LoginUser(account, password)), headers);
      loginResult = restTemplate.postForObject(callbackUrl, formEntity, LoginResult.class);
    } catch (Exception e) {
      LOG.error("login valid callback error", e);
      return new LoginResult(LoginStatus.CALLBACK_ERROR);
    }
    return loginResult == null ? new LoginResult(LoginStatus.ERROR) : loginResult;
  }
}

登錄用戶對(duì)象:

package com.hyh.sso.po;

/**
 * 登錄用戶對(duì)象
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 16:58
 */
public class LoginUser {

  /**
   * 賬號(hào)
   */
  private String account;
  /**
   * 密碼
   */
  private String password;

  /**
   * 登錄時(shí)間
   */
  private String loginTime;

  public LoginUser(String account, String password) {
    this.account = account;
    this.password = password;
  }
  public LoginUser() {

  }


  public String getAccount() {
    return account;
  }

  public void setAccount(String account) {
    this.account = account;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public String getLoginTime() {
    return loginTime;
  }

  public void setLoginTime(String loginTime) {
    this.loginTime = loginTime;
  }
}

用戶Token對(duì)象:

package com.hyh.sso.po;

import com.hyh.utils.code.MD5;
import com.hyh.utils.common.StringUtils;

import java.util.Calendar;

/**
 * 用戶Token對(duì)象
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 17:07
 */
public class UserToken {

  /**
   * token
   */
  private String token;

  /**
   * 過期時(shí)間
   */
  private String expireTime;

  public UserToken(String token, String expireTime) {
    this.token = token;
    this.expireTime = expireTime;
  }

  public UserToken() {

  }

  public static UserToken getUserToken() {
    Calendar nowTime = Calendar.getInstance();
    nowTime.add(Calendar.MINUTE, 30);
    return new UserToken(MD5.getMD5String(StringUtils.ranStr(32)), String.valueOf(nowTime.getTimeInMillis()));
  }

  public String getToken() {
    return token;
  }

  public void setToken(String token) {
    this.token = token;
  }

  public String getExpireTime() {
    return expireTime;
  }

  public void setExpireTime(String expireTime) {
    this.expireTime = expireTime;
  }

  /**
   * 生成Token
   */
  private String generateToken() {
    return MD5.getMD5String(StringUtils.ranStr(32));
  }
}

登錄結(jié)果對(duì)象:

package com.hyh.sso.po;

import com.hyh.sso.LoginStatus;
import com.hyh.sso.LoginTypes;

/**
 * 登錄結(jié)果對(duì)象
 * @Author: heyuhua
 * @Date: 2021/1/8 16:58
 */
public class LoginResult {
  /**
   * 登錄用戶對(duì)象
   */
  private LoginUser loginUser;
  /**
   * 登錄用戶令牌
   */
  private UserToken userToken;

  /**
   * 登錄狀態(tài)
   */
  private LoginStatus loginStatus;

  /**
   * 登錄類型
   */
  private LoginTypes loginTypes;

  public LoginResult(){}

  public LoginResult(LoginStatus loginStatus) {
    this.loginStatus = loginStatus;
  }

  public LoginUser getLoginUser() {
    return loginUser;
  }

  public void setLoginUser(LoginUser loginUser) {
    this.loginUser = loginUser;
  }

  public UserToken getUserToken() {
    return userToken;
  }

  public void setUserToken(UserToken userToken) {
    this.userToken = userToken;
  }

  public LoginStatus getLoginStatus() {
    return loginStatus;
  }

  public void setLoginStatus(LoginStatus loginStatus) {
    this.loginStatus = loginStatus;
  }

  public LoginTypes getLoginTypes() {
    return loginTypes;
  }

  public void setLoginTypes(LoginTypes loginTypes) {
    this.loginTypes = loginTypes;
  }

  @Override
  public String toString() {
    return "LoginResult{" +
        "loginUser=" + loginUser +
        ", userToken=" + userToken +
        ", loginStatus=" + loginStatus +
        ", loginTypes=" + loginTypes +
        '}';
  }
}

登錄助手:

package com.hyh.sso.helper;

import com.alibaba.fastjson.JSON;
import com.hyh.redis.helper.RedisHelper;
import com.hyh.sso.LoginStatus;
import com.hyh.sso.po.LoginResult;
import com.hyh.sso.po.LoginUser;
import com.hyh.sso.po.UserToken;
import com.hyh.sso.service.LoginService;
import com.hyh.utils.common.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 登錄助手
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 17:13
 */
@Component
public class LoginHelper {

  /**
   * 日志
   */
  private static final Logger LOG = LoggerFactory.getLogger(LoginHelper.class);

  /**
   * 登錄用戶信息KEY
   */
  private final String LOGIN_USER_KEY = "login:user:";
  /**
   * 登錄用戶TOKEN KEY
   */
  private final String LOGIN_TOKEN_KEY = "login:token:";
  /**
   * 登錄失敗統(tǒng)計(jì) KEY
   */
  private final String LOGIN_FAIL_COUNT_KEY = "login:fail:count";
  /**
   * 登錄失敗最多允許次數(shù)
   */
  private final long MAX_FAIL_COUNT = 5;


  /**
   * 登錄服務(wù)
   */
  @Resource
  private LoginService loginService;

  /**
   * redis助手
   */
  @Autowired
  private RedisHelper redisHelper;


  /**
   * 登錄
   *
   * @param account   用戶名
   * @param password  密碼
   * @param callbackUrl 回調(diào)URL
   * @return
   */
  public LoginResult login(String account, String password, String callbackUrl) {
    Assert.notNull(account, "account is null ");
    Assert.notNull(password, "password is null ");
    Assert.notNull(callbackUrl, "callbackUrl is null ");
    //判斷賬戶是否多次登錄失敗被鎖定
    String value = redisHelper.getStringValue(LOGIN_FAIL_COUNT_KEY + account);
    if (StringUtils.isNotBlank(value)) {
      Long loginFailCount = Long.parseLong(value);
      if (loginFailCount.longValue() >= MAX_FAIL_COUNT) {
        return new LoginResult(LoginStatus.ACCOUNT_LOCK);
      }
    }
    //登錄操作
    LoginResult loginResult = loginService.login(account, password, callbackUrl);
    switch (loginResult.getLoginStatus()) {
      case SUCCESS:
        //登錄成功
        loginSuccess(loginResult);
        break;
      case FAIL:
        //登錄失敗
        loginFail(loginResult);
        break;
      case ERROR:
        loginError(loginResult);
        //登錄異常
        break;
      default:
        break;
    }
    return loginResult;
  }

  /**
   * 注銷
   *
   * @param account
   * @param token
   */
  public void logout(String account, String token) {
    Assert.notNull(account, "account is null ");
    Assert.notNull(token, "token is null ");
    removeKey(account, token);
  }

  /**
   * 注銷
   *
   * @param token
   */
  public void logout(String token) {
    Assert.notNull(token, "token is null ");
    removeKey(token);
  }

  /**
   * 獲取登錄用戶
   *
   * @param token
   * @return
   */
  public LoginUser getLoginUser(String token) {
    Assert.notNull(token, "token is null ");
    String value = redisHelper.getStringValue(LOGIN_USER_KEY + token);
    if (StringUtils.isNotBlank(value)) {
      return JSON.parseObject(value, LoginUser.class);
    }
    return null;
  }

  /**
   * 移除 key
   *
   * @param account
   * @param token
   */
  private void removeKey(String account, String token) {
    redisHelper.del(LOGIN_FAIL_COUNT_KEY + account);
    redisHelper.del(LOGIN_TOKEN_KEY + account);
    redisHelper.del(LOGIN_USER_KEY + token);
  }

  /**
   * 移除 Key
   *
   * @param token
   */
  private void removeKey(String token) {
    redisHelper.del(LOGIN_USER_KEY + token);
    //其余的key到達(dá)過期時(shí)間自動(dòng)過期
  }


  /**
   * 登錄異常
   *
   * @param loginResult
   */
  private void loginError(LoginResult loginResult) {
    LOG.error("user 【" + loginResult.getLoginUser().getAccount() + "】 login error");
  }

  /**
   * 登錄失敗操作
   *
   * @param loginResult
   */
  private void loginFail(LoginResult loginResult) {
    String key = LOGIN_FAIL_COUNT_KEY + loginResult.getLoginUser();
    redisHelper.increment(key, 30 * 60 * 1000);
  }

  /**
   * 登錄成功操作
   *
   * @param loginResult
   */
  private void loginSuccess(LoginResult loginResult) {
    LoginUser loginUser = loginResult.getLoginUser();
    loginUser.setLoginTime(String.valueOf(new Date().getTime()));
    UserToken userToken = UserToken.getUserToken();
    redisHelper.set(LOGIN_TOKEN_KEY + loginResult.getLoginUser().getAccount(), JSON.toJSONString(userToken), 30, TimeUnit.MINUTES);
    redisHelper.set(LOGIN_USER_KEY + userToken.getToken(), JSON.toJSONString(loginUser), 30, TimeUnit.MINUTES);
    redisHelper.del(LOGIN_FAIL_COUNT_KEY + loginResult.getLoginUser());
  }
}

3.配置文件

代碼如下(示例):

server:
 port: 8088


spring:
 #redis配置
 redis:
  host: 192.168.6.134
  port: 30511
  password:

4.單元測(cè)試

測(cè)試代碼如下(示例):

 @Autowired
  private LoginHelper loginHelper;

  @Test
  public void testLogin() {
    //測(cè)試時(shí)先開啟HyhBootApplication
    String account = "hyh";
    String password = "hyh-pwd";
    String cllbackUrl = "http://localhost:8088/hyh/login";//在com.hyh.core.web下可查看
    LoginResult loginResult = loginHelper.login(account, password, cllbackUrl);
    System.out.println("loginResult:" + loginResult.toString());
  }
//控制層代碼
  @RequestMapping(value = "login", method = RequestMethod.POST)
  public LoginResult login(@RequestBody LoginUser loginUser) {
    Assert.notNull(loginUser.getAccount(), "account is null");
    Assert.notNull(loginUser.getPassword(), "password is null");
    LoginResult loginResult = new LoginResult(LoginStatus.SUCCESS);
    loginResult.setLoginUser(loginUser);
    //模擬直接返回登錄成功
    return loginResult;
  }

總結(jié)

是不是感覺很簡(jiǎn)單?更多用法請(qǐng)點(diǎn)擊下方查看源碼,關(guān)注我?guī)憬颐馗喔呒?jí)用法

源碼地址:點(diǎn)此查看源碼.

到此這篇關(guān)于SpringBoot SSO輕松實(shí)現(xiàn)(附demo)的文章就介紹到這了,更多相關(guān)SpringBoot SSO內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于springboot攔截器HandlerInterceptor的注入問題

    基于springboot攔截器HandlerInterceptor的注入問題

    這篇文章主要介紹了springboot攔截器HandlerInterceptor的注入問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • IntelliJ IDEA 2020常用配置設(shè)置大全(方便干活)

    IntelliJ IDEA 2020常用配置設(shè)置大全(方便干活)

    這篇文章主要介紹了IntelliJ IDEA 2020常用配置設(shè)置大全(方便干活),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Java?方法的重載與參數(shù)傳遞詳解

    Java?方法的重載與參數(shù)傳遞詳解

    在java中,方法就是用來完成解決某件事情或?qū)崿F(xiàn)某個(gè)功能的辦法。方法實(shí)現(xiàn)的過程中,會(huì)包含很多條語(yǔ)句用于完成某些有意義的功能——通常是處理文本,控制輸入或計(jì)算數(shù)值,這篇文章我們來探究一下方法的重載與傳參
    2022-04-04
  • Java原子變量類原理及實(shí)例解析

    Java原子變量類原理及實(shí)例解析

    這篇文章主要介紹了Java原子變量類原理及實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • 如何解決Could not transfer artifact org.springframework.boot問題

    如何解決Could not transfer artifact org.spri

    在Maven更新過程中遇到“Could not transfer artifact org.springframework.boot”錯(cuò)誤通常是由于網(wǎng)絡(luò)問題,解決方法是在Maven的設(shè)置中忽略HTTPS,添加特定語(yǔ)句后,可以正常下載依賴,但下載速度可能較慢,這是一種常見的解決方案,希望對(duì)遇到相同問題的人有所幫助
    2024-09-09
  • kotlin中const 和val的區(qū)別及使用場(chǎng)景分析

    kotlin中const 和val的區(qū)別及使用場(chǎng)景分析

    在 Kotlin 中,const 和 val 都是用來聲明常量的,但它們的使用場(chǎng)景和功能有所不同,下面給大家介紹kotlin中const 和val的區(qū)別,感興趣的朋友一起看看吧
    2025-04-04
  • SpringBoot+Quartz+數(shù)據(jù)庫(kù)存儲(chǔ)的完美集合

    SpringBoot+Quartz+數(shù)據(jù)庫(kù)存儲(chǔ)的完美集合

    這篇文章主要介紹了SpringBoot+Quartz+數(shù)據(jù)庫(kù)存儲(chǔ)的示例代碼,本文通過實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • Java環(huán)境中MyBatis與Spring或Spring MVC框架的集成方法

    Java環(huán)境中MyBatis與Spring或Spring MVC框架的集成方法

    和MyBatis類似,Spring或者Spring MVC框架在Web應(yīng)用程序的運(yùn)作中同樣主要負(fù)責(zé)處理數(shù)據(jù)庫(kù)事務(wù),這里我們就來看一下Java環(huán)境中MyBatis與Spring或Spring MVC框架的集成方法
    2016-06-06
  • SpringBoot中干掉Whitelabel Error Page返回自定義內(nèi)容的實(shí)現(xiàn)

    SpringBoot中干掉Whitelabel Error Page返回自定義內(nèi)容的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot中干掉Whitelabel Error Page返回自定義內(nèi)容的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Spring的@CrossOrigin注解使用與CrossFilter對(duì)象自定義詳解

    Spring的@CrossOrigin注解使用與CrossFilter對(duì)象自定義詳解

    這篇文章主要介紹了Spring的@CrossOrigin注解使用與CrossFilter對(duì)象自定義詳解,跨域,指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本,它是由瀏覽器的同源策略造成的,是瀏覽器施加的安全限制,所謂同源是指,域名,協(xié)議,端口均相同,需要的朋友可以參考下
    2023-12-12

最新評(píng)論

东乌珠穆沁旗| 社旗县| 武功县| 全州县| 永新县| 讷河市| 托克逊县| 钟山县| 长寿区| 安溪县| 林口县| 彝良县| 泉州市| 高碑店市| 潼关县| 新河县| 察隅县| 洪雅县| 巴林右旗| 阳新县| 安泽县| 新沂市| 长葛市| 麻阳| 遂平县| 英超| 呼和浩特市| 米易县| 宜川县| 西乌珠穆沁旗| 那坡县| 贺州市| 万宁市| 大竹县| 名山县| 新龙县| 合江县| 鄂州市| 南昌市| 明水县| 泰安市|