這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)怎么在SpringBoot中使用token實(shí)現(xiàn)一個(gè)登錄校驗(yàn)功能,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
創(chuàng)新互聯(lián)建站是一家專業(yè)提供牟平企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、H5頁(yè)面制作、小程序制作等業(yè)務(wù)。10年已為牟平眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進(jìn)行中。
1、基于session登錄
基于session的登錄(有回話狀態(tài)),用戶攜帶賬號(hào)密碼發(fā)送請(qǐng)求向服務(wù)器,服務(wù)器進(jìn)行判斷,成功后將用戶信息放入session,用戶發(fā)送請(qǐng)求判斷session中是否有用戶信息,有的話放行,沒(méi)有的話進(jìn)行攔截,但是考慮到時(shí)App產(chǎn)品,牽扯到要判斷用戶的session,需要sessionID,還要根據(jù)sessionId來(lái)獲取session,在進(jìn)行校驗(yàn),還有sessionId的一個(gè)存儲(chǔ)等等,所以沒(méi)考慮用session
2、基于token登錄
基于token的登錄,是不存在回話狀態(tài),大概思路,在用戶初次等路的時(shí)候,校驗(yàn)用戶賬號(hào)密碼,成功后給其生成一個(gè)token,token=用戶ID+時(shí)間戳+過(guò)期時(shí)間+一個(gè)自己平臺(tái)規(guī)定的簽名,使用jjwt生成一個(gè)令牌,然后對(duì)其進(jìn)行存庫(kù),用戶每次訪問(wèn)接口,都會(huì)在頭部Headers中帶上token,后來(lái)攔截器對(duì)其進(jìn)行攔截,如果token為空或錯(cuò)誤則讓其登錄,如果有token,獲取token進(jìn)行其解析,取出里面的用戶ID,根據(jù)用戶ID查詢數(shù)據(jù)庫(kù)中所存token,判斷其是否正確,正確使其登錄,錯(cuò)誤則提示登錄,大致思路就是這樣,下面開始代碼
導(dǎo)入jar包
<!-- 生成token --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency>
開發(fā)步驟
1、創(chuàng)建token庫(kù)
2、創(chuàng)建token實(shí)體類
package com.prereadweb.user.entity; import lombok.Data; /** * @Description: Token實(shí)體類 * @author: Yangxf * @date: 2019/4/14 12:53 */ @Data public class TokenEntity { /* tokenId */ private Long id; /* 用戶ID */ private Long userId; /* 刷新時(shí)間 */ private int buildTime; /* token */ private String token; }
3、編寫token的三個(gè)方法(添加、查詢、修改)
package com.prereadweb.user.mapper; import com.prereadweb.user.entity.TokenEntity; import org.apache.ibatis.annotations.Mapper; /** * @Description: Token數(shù)據(jù)庫(kù)持久層接口 * @author: Yangxf * @date: 2019/4/14 13:00 */ @Mapper public interface TokenMapper { /* 添加token */ void addToken(TokenEntity token); /* 修改token */ void updataToken(TokenEntity token); /* 查詢token */ TokenEntity findByUserId(Long userId); }
4、創(chuàng)建攔截器
package com.prereadweb.user.interceptor; import com.prereadweb.user.entity.TokenEntity; import com.prereadweb.user.mapper.TokenMapper; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Date; /** * @Description:攔截器 * @author: Yangxf * @date: 2019/4/14 12:58 */ public class LoginInterceptor implements HandlerInterceptor { @Autowired protected TokenMapper tokenMapper; //提供查詢 @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {} @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {} @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { //此處為不需要登錄的接口放行 if (arg0.getRequestURI().contains("/login") || arg0.getRequestURI().contains("/register") || arg0.getRequestURI().contains("/error") || arg0.getRequestURI().contains("/static")) { return true; } //權(quán)限路徑攔截 //PrintWriter resultWriter = arg1.getOutputStream(); // TODO: 有時(shí)候用PrintWriter 回報(bào) getWriter() has already been called for this response //換成ServletOutputStream就OK了 arg1.setContentType("text/html;charset=utf-8"); ServletOutputStream resultWriter = arg1.getOutputStream(); final String headerToken=arg0.getHeader("token"); //判斷請(qǐng)求信息 if(null==headerToken||headerToken.trim().equals("")){ resultWriter.write("你沒(méi)有token,需要登錄".getBytes()); resultWriter.flush(); resultWriter.close(); return false; } //解析Token信息 try { Claims claims = Jwts.parser().setSigningKey("preRead").parseClaimsJws(headerToken).getBody(); String tokenUserId=(String)claims.get("userId"); long iTokenUserId = Long.parseLong(tokenUserId); //根據(jù)客戶Token查找數(shù)據(jù)庫(kù)Token TokenEntity myToken= tokenMapper.findByUserId(iTokenUserId); //數(shù)據(jù)庫(kù)沒(méi)有Token記錄 if(null==myToken) { resultWriter.write("我沒(méi)有你的token?,需要登錄".getBytes()); resultWriter.flush(); resultWriter.close(); return false; } //數(shù)據(jù)庫(kù)Token與客戶Token比較 if( !headerToken.equals(myToken.getToken()) ){ resultWriter.print("你的token修改過(guò)?,需要登錄"); resultWriter.flush(); resultWriter.close(); return false; } //判斷Token過(guò)期 Date tokenDate= claims.getExpiration(); int overTime=(int)(new Date().getTime()-tokenDate.getTime())/1000; if(overTime>60*60*24*3){ resultWriter.write("你的token過(guò)期了?,需要登錄".getBytes()); resultWriter.flush(); resultWriter.close(); return false; } } catch (Exception e) { resultWriter.write("反正token不對(duì),需要登錄".getBytes()); resultWriter.flush(); resultWriter.close(); return false; } //最后才放行 return true; } }
5、配置攔截器
package com.prereadweb.user.config; import com.prereadweb.user.interceptor.LoginInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @Description: 攔截器配置 * @author: Yangxf * @date: 2019/4/14 13:09 */ @Configuration public class LoginConfiguration implements WebMvcConfigurer { /** * @Function: 這個(gè)方法才能在攔截器中自動(dòng)注入查詢數(shù)據(jù)庫(kù)的對(duì)象 * @author: YangXueFeng * @Date: 2019/4/14 13:10 */ @Bean LoginInterceptor loginInterceptor() { return new LoginInterceptor(); } /** * @Function: 配置生成器:添加一個(gè)攔截器,攔截路徑為login以后的路徑 * @author: YangXueFeng * @Date: 2019/4/14 13:10 */ @Override public void addInterceptors(InterceptorRegistry registry ){ registry.addInterceptor(loginInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/register", "/static"); } }
6、登錄
controller層
@RequestMapping("/getlogin") public Object login(@Param("..") LoginQueryForm loginForm) { return userViewService.login(loginForm); }
serrvice層
@Override public Map<String, Object> login(LoginQueryForm loginForm) { Map<String, Object> map = new HashMap<>(); //手機(jī)驗(yàn)證碼登錄 if(!Util.isEmpty(loginForm.getPhoneCode())) { return phoneCodeLogin(loginForm, map); } //判斷用戶信息為空 if (Util.isEmpty(loginForm.getPhone()) || Util.isEmpty(loginForm.getLoginPwd())) { return checkParameter(map); } //根據(jù)手機(jī)號(hào)查詢user對(duì)象 UserEntity user = userMapper.getUser(loginForm.getPhone()); //判斷用戶不存在 if (Util.isEmpty(user)) { map.put("code", UserStatusEnum.USER_NON_EXISTENT.intKey()); map.put("msg", UserStatusEnum.USER_NON_EXISTENT.value()); return map; } /* 判斷密碼 */ if(!MD5Util.string2MD5(loginForm.getLoginPwd()).equals(user.getLoginPwd())){ map.put("code", UserStatusEnum.PWD_ERROR.intKey()); map.put("msg", UserStatusEnum.PWD_ERROR.value()); return map; } //根據(jù)數(shù)據(jù)庫(kù)的用戶信息查詢Token return operateToKen(map, user, user.getId()); }
token操作
private Map<String, Object> operateToKen(Map<String, Object> map, UserEntity user, long userId) { //根據(jù)數(shù)據(jù)庫(kù)的用戶信息查詢Token TokenEntity token = tokenmapper.findByUserId(userId); //為生成Token準(zhǔn)備 String TokenStr = ""; Date date = new Date(); int nowTime = (int) (date.getTime() / 1000); //生成Token TokenStr = creatToken(userId, date); if (null == token) { //第一次登陸 token = new TokenEntity(); token.setToken(TokenStr); token.setBuildTime(nowTime); token.setUserId(userId); token.setId(Long.valueOf(IdUtils.getPrimaryKey())); tokenmapper.addToken(token); }else{ //登陸就更新Token信息 TokenStr = creatToken(userId, date); token.setToken(TokenStr); token.setBuildTime(nowTime); tokenmapper.updataToken(token); } UserQueryForm queryForm = getUserInfo(user, TokenStr); /* 將用戶信息存入session */ /*SessionContext sessionContext = SessionContext.getInstance(); HttpSession session = sessionContext.getSession(); httpSession.setAttribute("userInfo", user);*/ //返回Token信息給客戶端 successful(map); map.put("data", queryForm); return map; }
生成token
private String creatToken(Long userId, Date date) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT") // 設(shè)置header .setHeaderParam("alg", "HS256").setIssuedAt(date) // 設(shè)置簽發(fā)時(shí)間 .setExpiration(new Date(date.getTime() + 1000 * 60 * 60)) .claim("userId",String.valueOf(userId) ) // 設(shè)置內(nèi)容 .setIssuer("lws")// 設(shè)置簽發(fā)人 .signWith(signatureAlgorithm, "簽名"); // 簽名,需要算法和key String jwt = builder.compact(); return jwt; }
上述就是小編為大家分享的怎么在SpringBoot中使用token實(shí)現(xiàn)一個(gè)登錄校驗(yàn)功能了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
分享文章:怎么在SpringBoot中使用token實(shí)現(xiàn)一個(gè)登錄校驗(yàn)功能
轉(zhuǎn)載來(lái)于:http://jinyejixie.com/article28/ggscjp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、動(dòng)態(tài)網(wǎng)站、網(wǎng)站策劃、企業(yè)建站、、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
網(wǎng)頁(yè)設(shè)計(jì)公司知識(shí)