欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

前言

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

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

一、技術(shù)介紹

1.SSO是什么?

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

二、使用步驟

1.引入maven庫

代碼如下(示例):

 <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 用戶驗證回調(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 {

}

登錄接口實現(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;

/**
 * 登錄接口實現(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接口請求模板
   */
  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è)置請求媒體數(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;
  }
}

登錄用戶對象:

package com.hyh.sso.po;

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

  /**
   * 賬號
   */
  private String account;
  /**
   * 密碼
   */
  private String password;

  /**
   * 登錄時間
   */
  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對象:

package com.hyh.sso.po;

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

import java.util.Calendar;

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

  /**
   * token
   */
  private String token;

  /**
   * 過期時間
   */
  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é)果對象:

package com.hyh.sso.po;

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

/**
 * 登錄結(jié)果對象
 * @Author: heyuhua
 * @Date: 2021/1/8 16:58
 */
public class LoginResult {
  /**
   * 登錄用戶對象
   */
  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)計 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á)過期時間自動過期
  }


  /**
   * 登錄異常
   *
   * @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.單元測試

測試代碼如下(示例):

 @Autowired
  private LoginHelper loginHelper;

  @Test
  public void testLogin() {
    //測試時先開啟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é)

是不是感覺很簡單?更多用法請點擊下方查看源碼,關(guān)注我?guī)憬颐馗喔呒売梅?/p>

源碼地址:點此查看源碼.

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

相關(guān)文章

  • Spring boot jpa 刪除數(shù)據(jù)和事務(wù)管理的問題實例詳解

    Spring boot jpa 刪除數(shù)據(jù)和事務(wù)管理的問題實例詳解

    這篇文章主要介紹了Spring boot jpa 刪除數(shù)據(jù)和事務(wù)管理的問題實例詳解,涉及業(yè)務(wù)場景的一些知識和遇到的的問題,需要的朋友可以參考。
    2017-09-09
  • Redis監(jiān)聽過期的key實現(xiàn)流程詳解

    Redis監(jiān)聽過期的key實現(xiàn)流程詳解

    本文主要介紹了Redis監(jiān)聽key的過期時間,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Java中字符串去重的特性介紹

    Java中字符串去重的特性介紹

    這篇文章主要介紹了Java中字符串去重的特性,是Java8中引入的一個新特性,至于是否真的用起來順手就見仁見智了...需要的朋友可以參考下
    2015-07-07
  • 詳解java.lang.reflect.Modifier.isInterface()方法

    詳解java.lang.reflect.Modifier.isInterface()方法

    這篇文章主要介紹了詳解java.lang.reflect.Modifier.isInterface()方法的相關(guān)資料,這里提供實例幫助大家理解這個方法的使用,需要的朋友可以參考下
    2017-09-09
  • Java代理模式的示例詳解

    Java代理模式的示例詳解

    代理模式(Proxy Parttern)為一個對象提供一個替身,來控制這個對象的訪問,即通過代理對象來訪問目標(biāo)對象。本文將通過示例詳細(xì)講解一下這個模式,需要的可以參考一下
    2022-02-02
  • java語言圖形用戶登錄界面代碼

    java語言圖形用戶登錄界面代碼

    這篇文章主要為大家詳細(xì)介紹了java語言圖形用戶登錄界面代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • SpringBoot用配置影響B(tài)ean加載@ConditionalOnProperty

    SpringBoot用配置影響B(tài)ean加載@ConditionalOnProperty

    這篇文章主要為大家介紹了SpringBoot用配置影響B(tài)ean加載@ConditionalOnProperty示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Java中檢查值是否存在于數(shù)組中的4種詳細(xì)方法

    Java中檢查值是否存在于數(shù)組中的4種詳細(xì)方法

    這篇文章主要給大家介紹了關(guān)于Java中檢查值是否存在于數(shù)組中的4種詳細(xì)方法,相信大家在操作Java的時候經(jīng)常會要檢查一個數(shù)組(無序)是否包含一個特定的值,需要的朋友可以參考下
    2023-08-08
  • Java面試必備八股文整理

    Java面試必備八股文整理

    這篇文章主要介紹了Java面試必備八股文整理,小伙伴們出去面試的時候會被問到很多java專業(yè)性的知識,那么八股文就是為此而出現(xiàn)的,需要的朋友可以參考下
    2023-03-03
  • 實例講解java的純數(shù)字加密解密

    實例講解java的純數(shù)字加密解密

    本文給大家分享的是一個java純數(shù)字加密解密技術(shù),加密和解密本身就是一對共生體,缺一不可,需要的朋友可以參考下
    2015-07-07

最新評論