完成单点登录
編寫登錄接口
接下來,我們需要在auth編寫一個(gè)接口,對外提供登錄授權(quán)服務(wù)。基本流程如下:
-
客戶端攜帶用戶名和密碼請求登錄
-
授權(quán)中心調(diào)用用戶中心接口,根據(jù)用戶名和密碼查詢用戶信息
-
如果用戶名密碼正確,能獲取用戶,否則登錄失敗
-
如果校驗(yàn)成功,則生成JWT并返回
編寫遠(yuǎn)程調(diào)用接口
創(chuàng)建ums-interface工程:
pom.xml中的依賴,參照其他interface工程。并在ums和auth工程中引入該接口工程
UmsApi:
public interface UmsApi {/*** 根據(jù)用戶名和密碼查詢用戶* @param username* @param password* @return*/@GetMapping("ums/member/query")public Resp<MemberEntity> queryUser(@RequestParam("username") String username,@RequestParam("password") String password); }生成公鑰和私鑰
我們需要在授權(quán)中心生成真正的公鑰和私鑰。我們必須有一個(gè)生成公鑰和私鑰的secret,這個(gè)可以配置到application.yml中:
jwt:pubKeyPath: C:\\tmp\\rsa\\rsa.pub # 公鑰地址priKeyPath: C:\\tmp\\rsa\\rsa.pri # 私鑰地址secret: sf3423jsdf#3$@FDS32expire: 30 # 過期時(shí)間,單位分鐘cookieName: TOKEN然后編寫屬性類讀取jwt配置,并從秘鑰配置文件中讀取出響應(yīng)的公鑰及私鑰,加載這些數(shù)據(jù):
@Data @Slf4j @ConfigurationProperties(prefix = "jwt") public class JwtProperties {private String secret; // 密鑰private String pubKeyPath;// 公鑰private String priKeyPath;// 私鑰private int expire;// token過期時(shí)間private PublicKey publicKey; // 公鑰private PrivateKey privateKey; // 私鑰private String cookieName; // cookie名稱/*** @PostContruct:在構(gòu)造方法執(zhí)行之后執(zhí)行該方法*/@PostConstructpublic void init() {try {File pubKey = new File(pubKeyPath);File priKey = new File(priKeyPath);if (!pubKey.exists() || !priKey.exists()) {// 生成公鑰和私鑰RsaUtils.generateKey(pubKeyPath, priKeyPath, secret);}// 獲取公鑰和私鑰this.publicKey = RsaUtils.getPublicKey(pubKeyPath);this.privateKey = RsaUtils.getPrivateKey(priKeyPath);} catch (Exception e) {log.error("初始化公鑰和私鑰失敗!", e);throw new RuntimeException();}} }AuthController
編寫授權(quán)接口,我們接收用戶名和密碼,校驗(yàn)成功后,寫入cookie中。
-
請求方式:post
-
請求路徑:/auth/accredit
-
請求參數(shù):username和password
-
返回結(jié)果:無
代碼:
@RestController @RequestMapping("auth") @EnableConfigurationProperties(JwtProperties.class) public class AuthController {@Autowiredprivate AuthService authService;@Autowiredprivate JwtProperties jwtProperties;/*** 登錄授權(quán)** @param username* @param password* @return*/@PostMapping("accredit")public Resp<Object> authentication(@RequestParam("username") String username,@RequestParam("password") String password,HttpServletRequest request,HttpServletResponse response) {// 登錄校驗(yàn)String token = this.authService.authentication(username, password);if (StringUtils.isBlank(token)) {return Resp.fail("登錄失敗,用戶名或密碼錯(cuò)誤");}// 將token寫入cookie,并指定httpOnly為true,防止通過JS獲取和修改CookieUtils.setCookie(request, response, jwtProperties.getCookieName(), token, jwtProperties.getExpire());return Resp.ok("登錄成功");} }AuthService
在auth-service:
@Service public class AuthService {@Autowiredprivate UmsClient umsClient;@Autowiredprivate JwtProperties jwtProperties;public String authentication(String username, String password) {try {// 調(diào)用微服務(wù),執(zhí)行查詢Resp<MemberEntity> resp = this.umsClient.queryUser(username, password);MemberEntity memberEntity = resp.getData();// 如果查詢結(jié)果為null,則直接返回nullif (memberEntity == null) {return null;}// 如果有查詢結(jié)果,則生成tokenMap<String, Object> map = new HashMap<>();map.put("id", memberEntity.getId());map.put("username", memberEntity.getUsername());String token = JwtUtils.generateToken(map, jwtProperties.getPrivateKey(), jwtProperties.getExpire());return token;} catch (Exception e) {e.printStackTrace();}return null;} }UmsClient
接下來我們肯定要對用戶密碼進(jìn)行校驗(yàn),所以我們需要通過FeignClient去訪問 ums-service微服務(wù):
在auth中引入ums-interface依賴:
<dependency><groupId>com.atguigu</groupId><artifactId>ums-interface</artifactId><version>0.0.1-SNAPSHOT</version> </dependency>編寫UmsClient:
@FeignClient("ums-service") public interface UmsClient extends UmsApi { }CookieUtils
要注意,這里我們使用了一個(gè)工具類,CookieUtils,可以在課前資料中找到,我們把它添加到core中,然后引入servlet相關(guān)依賴即可:
package com.leon.core.utils;import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder;/*** * Cookie 工具類**/ public final class CookieUtils {static final Logger logger = LoggerFactory.getLogger(CookieUtils.class);/*** 得到Cookie的值, 不編碼* * @param request* @param cookieName* @return*/public static String getCookieValue(HttpServletRequest request, String cookieName) {return getCookieValue(request, cookieName, false);}/*** 得到Cookie的值,* * @param request* @param cookieName* @return*/public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {Cookie[] cookieList = request.getCookies();if (cookieList == null || cookieName == null){return null; }String retValue = null;try {for (int i = 0; i < cookieList.length; i++) {if (cookieList[i].getName().equals(cookieName)) {if (isDecoder) {retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");} else {retValue = cookieList[i].getValue();}break;}}} catch (UnsupportedEncodingException e) {logger.error("Cookie Decode Error.", e);}return retValue;}/*** 得到Cookie的值,* * @param request* @param cookieName* @return*/public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {Cookie[] cookieList = request.getCookies();if (cookieList == null || cookieName == null){return null; }String retValue = null;try {for (int i = 0; i < cookieList.length; i++) {if (cookieList[i].getName().equals(cookieName)) {retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);break;}}} catch (UnsupportedEncodingException e) {logger.error("Cookie Decode Error.", e);}return retValue;}/*** 生成cookie,并指定編碼* @param request 請求* @param response 響應(yīng)* @param cookieName name* @param cookieValue value* @param encodeString 編碼*/public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, String encodeString) {setCookie(request,response,cookieName,cookieValue,null,encodeString, null);}/*** 生成cookie,并指定生存時(shí)間* @param request 請求* @param response 響應(yīng)* @param cookieName name* @param cookieValue value* @param cookieMaxAge 生存時(shí)間*/public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge) {setCookie(request,response,cookieName,cookieValue,cookieMaxAge,null, null);}/*** 設(shè)置cookie,不指定httpOnly屬性*/public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge, String encodeString) {setCookie(request,response,cookieName,cookieValue,cookieMaxAge,encodeString, null);}/*** 設(shè)置Cookie的值,并使其在指定時(shí)間內(nèi)生效* * @param cookieMaxAge* cookie生效的最大秒數(shù)*/public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge, String encodeString, Boolean httpOnly) {try {if(StringUtils.isBlank(encodeString)) {encodeString = "utf-8";}if (cookieValue == null) {cookieValue = "";} else {cookieValue = URLEncoder.encode(cookieValue, encodeString);}Cookie cookie = new Cookie(cookieName, cookieValue);if (cookieMaxAge != null && cookieMaxAge > 0)cookie.setMaxAge(cookieMaxAge);if (null != request)// 設(shè)置域名的cookiecookie.setDomain(getDomainName(request));cookie.setPath("/");if(httpOnly != null) {cookie.setHttpOnly(httpOnly);}response.addCookie(cookie);} catch (Exception e) {logger.error("Cookie Encode Error.", e);}}/*** 得到cookie的域名*/private static final String getDomainName(HttpServletRequest request) {String domainName = null;String serverName = request.getRequestURL().toString();if (serverName == null || serverName.equals("")) {domainName = "";} else {serverName = serverName.toLowerCase();serverName = serverName.substring(7);final int end = serverName.indexOf("/");serverName = serverName.substring(0, end);final String[] domains = serverName.split("\\.");int len = domains.length;if (len > 3) {// www.xxx.com.cndomainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];} else if (len <= 3 && len > 1) {// xxx.com or xxx.cndomainName = domains[len - 2] + "." + domains[len - 1];} else {domainName = serverName;}}if (domainName != null && domainName.indexOf(":") > 0) {String[] ary = domainName.split("\\:");domainName = ary[0];}return domainName;}}?
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
- 上一篇: jwt工具类介绍
- 下一篇: 编写网关过滤器统一校验登录状态