當(dāng)前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
SpringBoot SSO整合
生活随笔
收集整理的這篇文章主要介紹了
SpringBoot SSO整合
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
SpringBoot系列-SSO整合
- SpringBoot整合SSO教程
- 前言
- 一、技術(shù)介紹
- 1.SSO是什么?
- 二、使用步驟
- 1.引入maven庫
- 2.具體使用示例
- 3.配置文件
- 4.單元測試
- 總結(jié)
SpringBoot整合SSO教程
提示:如有疑問請私信聯(lián)系、下方有源代碼地址,請自行拿取
前言
網(wǎng)上SSO的框架很多,此篇文章使用的是自寫的SSO來實(shí)現(xià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)是不需要管理員對用戶的登錄狀態(tài)或其他信息進(jìn)行修改的,這意味著在多個(gè)應(yīng)用系統(tǒng)中,用戶只需一次登錄就可以訪問所有相互信任的應(yīng)用系統(tǒng)。這種方式減少了由登錄產(chǎn)生的時(shí)間消耗,輔助了用戶管理,是目前比較流行的。二、使用步驟
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 用戶驗(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接口請求模板*/private static RestTemplate restTemplate = new RestTemplate();@Overridepublic 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;/*** 登錄時(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對象:
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;/*** 過期時(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é)果對象:
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;}@Overridepublic 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ù)*/@Resourceprivate LoginService loginService;/*** redis助手*/@Autowiredprivate 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: 8088spring:#redis配置redis:host: 192.168.6.134port: 30511password:4.單元測試
測試代碼如下(示例):
@Autowiredprivate LoginHelper loginHelper;@Testpublic void testLogin() {//測試時(shí)先開啟HyhBootApplicationString 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é)
是不是感覺很簡單?更多用法請點(diǎn)擊下方查看源碼,關(guān)注我?guī)憬颐馗喔呒売梅?/font>
源碼地址:點(diǎn)此查看源碼.
總結(jié)
以上是生活随笔為你收集整理的SpringBoot SSO整合的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【剑指 Java】第 1 弹:靠这份 J
- 下一篇: java compiler类_利用 Ja