詳解Spring Boot實(shí)戰(zhàn)之Filter實(shí)現(xiàn)使用JWT進(jìn)行接口認(rèn)證
本文介紹了spring Boot實(shí)戰(zhàn)之Filter實(shí)現(xiàn)使用JWT進(jìn)行接口認(rèn)證,分享給大家
jwt(json web token)
用戶發(fā)送按照約定,向服務(wù)端發(fā)送 Header、Payload 和 Signature,并包含認(rèn)證信息(密碼),驗(yàn)證通過(guò)后服務(wù)端返回一個(gè)token,之后用戶使用該token作為登錄憑證,適合于移動(dòng)端和api
jwt使用流程

本文示例接上面幾篇文章中的代碼進(jìn)行編寫(xiě),請(qǐng)閱讀本文的同時(shí)可以參考前面幾篇文章
1、添加依賴庫(kù)jjwt,本文中構(gòu)造jwt及解析jwt都使用了jjwt庫(kù)
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.6.0</version> </dependency>
2、添加登錄獲取token時(shí),所需要的認(rèn)證信息類LoginPara.Java
package com.xiaofangtech.sunt.jwt;
public class LoginPara {
private String clientId;
private String userName;
private String password;
private String captchaCode;
private String captchaValue;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCaptchaCode() {
return captchaCode;
}
public void setCaptchaCode(String captchaCode) {
this.captchaCode = captchaCode;
}
public String getCaptchaValue() {
return captchaValue;
}
public void setCaptchaValue(String captchaValue) {
this.captchaValue = captchaValue;
}
}
3、添加構(gòu)造jwt及解析jwt的幫助類JwtHelper.java
package com.xiaofangtech.sunt.jwt;
import java.security.Key;
import java.util.Date;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
public class JwtHelper {
public static Claims parseJWT(String jsonWebToken, String base64Security){
try
{
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
.parseClaimsJws(jsonWebToken).getBody();
return claims;
}
catch(Exception ex)
{
return null;
}
}
public static String createJWT(String name, String userId, String role,
String audience, String issuer, long TTLMillis, String base64Security)
{
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//生成簽名密鑰
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//添加構(gòu)成JWT的參數(shù)
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
.claim("role", role)
.claim("unique_name", name)
.claim("userid", userId)
.setIssuer(issuer)
.setAudience(audience)
.signWith(signatureAlgorithm, signingKey);
//添加Token過(guò)期時(shí)間
if (TTLMillis >= 0) {
long expMillis = nowMillis + TTLMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp).setNotBefore(now);
}
//生成JWT
return builder.compact();
}
}
4、添加token返回結(jié)果類AccessToken.java
package com.xiaofangtech.sunt.jwt;
public class AccessToken {
private String access_token;
private String token_type;
private long expires_in;
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getToken_type() {
return token_type;
}
public void setToken_type(String token_type) {
this.token_type = token_type;
}
public long getExpires_in() {
return expires_in;
}
public void setExpires_in(long expires_in) {
this.expires_in = expires_in;
}
}
5、添加獲取token的接口,通過(guò)傳入用戶認(rèn)證信息(用戶名、密碼)進(jìn)行認(rèn)證獲取
package com.xiaofangtech.sunt.jwt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xiaofangtech.sunt.bean.UserInfo;
import com.xiaofangtech.sunt.repository.UserInfoRepository;
import com.xiaofangtech.sunt.utils.MyUtils;
import com.xiaofangtech.sunt.utils.ResultMsg;
import com.xiaofangtech.sunt.utils.ResultStatusCode;
@RestController
public class JsonWebToken {
@Autowired
private UserInfoRepository userRepositoy;
@Autowired
private Audience audienceEntity;
@RequestMapping("oauth/token")
public Object getAccessToken(@RequestBody LoginPara loginPara)
{
ResultMsg resultMsg;
try
{
if(loginPara.getClientId() == null
|| (loginPara.getClientId().compareTo(audienceEntity.getClientId()) != 0))
{
resultMsg = new ResultMsg(ResultStatusCode.INVALID_CLIENTID.getErrcode(),
ResultStatusCode.INVALID_CLIENTID.getErrmsg(), null);
return resultMsg;
}
//驗(yàn)證碼校驗(yàn)在后面章節(jié)添加
//驗(yàn)證用戶名密碼
UserInfo user = userRepositoy.findUserInfoByName(loginPara.getUserName());
if (user == null)
{
resultMsg = new ResultMsg(ResultStatusCode.INVALID_PASSWORD.getErrcode(),
ResultStatusCode.INVALID_PASSWORD.getErrmsg(), null);
return resultMsg;
}
else
{
String md5Password = MyUtils.getMD5(loginPara.getPassword()+user.getSalt());
if (md5Password.compareTo(user.getPassword()) != 0)
{
resultMsg = new ResultMsg(ResultStatusCode.INVALID_PASSWORD.getErrcode(),
ResultStatusCode.INVALID_PASSWORD.getErrmsg(), null);
return resultMsg;
}
}
//拼裝accessToken
String accessToken = JwtHelper.createJWT(loginPara.getUserName(), String.valueOf(user.getName()),
user.getRole(), audienceEntity.getClientId(), audienceEntity.getName(),
audienceEntity.getExpiresSecond() * 1000, audienceEntity.getBase64Secret());
//返回accessToken
AccessToken accessTokenEntity = new AccessToken();
accessTokenEntity.setAccess_token(accessToken);
accessTokenEntity.setExpires_in(audienceEntity.getExpiresSecond());
accessTokenEntity.setToken_type("bearer");
resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(),
ResultStatusCode.OK.getErrmsg(), accessTokenEntity);
return resultMsg;
}
catch(Exception ex)
{
resultMsg = new ResultMsg(ResultStatusCode.SYSTEM_ERR.getErrcode(),
ResultStatusCode.SYSTEM_ERR.getErrmsg(), null);
return resultMsg;
}
}
}
6、添加使用jwt認(rèn)證的filter
package com.xiaofangtech.sunt.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaofangtech.sunt.jwt.Audience;
import com.xiaofangtech.sunt.jwt.JwtHelper;
import com.xiaofangtech.sunt.utils.ResultMsg;
import com.xiaofangtech.sunt.utils.ResultStatusCode;
public class HTTPBearerAuthorizeAttribute implements Filter{
@Autowired
private Audience audienceEntity;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
filterConfig.getServletContext());
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
ResultMsg resultMsg;
HttpServletRequest httpRequest = (HttpServletRequest)request;
String auth = httpRequest.getHeader("Authorization");
if ((auth != null) && (auth.length() > 7))
{
String HeadStr = auth.substring(0, 6).toLowerCase();
if (HeadStr.compareTo("bearer") == 0)
{
auth = auth.substring(7, auth.length());
if (JwtHelper.parseJWT(auth, audienceEntity.getBase64Secret()) != null)
{
chain.doFilter(request, response);
return;
}
}
}
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json; charset=utf-8");
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ObjectMapper mapper = new ObjectMapper();
resultMsg = new ResultMsg(ResultStatusCode.INVALID_TOKEN.getErrcode(), ResultStatusCode.INVALID_TOKEN.getErrmsg(), null);
httpResponse.getWriter().write(mapper.writeValueAsString(resultMsg));
return;
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
7、在入口處注冊(cè)filter
package com.xiaofangtech.sunt;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import com.xiaofangtech.sunt.filter.HTTPBasicAuthorizeAttribute;
import com.xiaofangtech.sunt.filter.HTTPBearerAuthorizeAttribute;
import com.xiaofangtech.sunt.jwt.Audience;
@SpringBootApplication
@EnableConfigurationProperties(Audience.class)
public class SpringRestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringRestApplication.class, args);
}
@Bean
public FilterRegistrationBean basicFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
HTTPBasicAuthorizeAttribute httpBasicFilter = new HTTPBasicAuthorizeAttribute();
registrationBean.setFilter(httpBasicFilter);
List<String> urlPatterns = new ArrayList<String>();
urlPatterns.add("/user/getuser");
registrationBean.setUrlPatterns(urlPatterns);
return registrationBean;
}
@Bean
public FilterRegistrationBean jwtFilterRegistrationBean(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
HTTPBearerAuthorizeAttribute httpBearerFilter = new HTTPBearerAuthorizeAttribute();
registrationBean.setFilter(httpBearerFilter);
List<String> urlPatterns = new ArrayList<String>();
urlPatterns.add("/user/getusers");
registrationBean.setUrlPatterns(urlPatterns);
return registrationBean;
}
}
8、添加獲取md5的方法類MyUtils
package com.xiaofangtech.sunt.utils;
import java.security.MessageDigest;
public class MyUtils {
public static String getMD5(String inStr) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
}
9、在返回信息類中補(bǔ)充添加錯(cuò)誤碼
INVALID_CLIENTID(30003, "Invalid clientid"), INVALID_PASSWORD(30004, "User name or password is incorrect"), INVALID_CAPTCHA(30005, "Invalid captcha or captcha overdue"), INVALID_TOKEN(30006, "Invalid token");
10、代碼中涉及的Audience類,在上一篇文章中定義,本文不再重復(fù)說(shuō)明
11、代碼整體結(jié)構(gòu)

12、測(cè)試
1) 獲取token,傳入用戶認(rèn)證信息

認(rèn)證通過(guò)返回token信息

2) 使用上面獲取的token進(jìn)行接口調(diào)用
未使用token,獲取token錯(cuò)誤,或者token過(guò)期時(shí)

使用正確的token時(shí)

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Vue+Jwt+SpringBoot+Ldap完成登錄認(rèn)證的示例代碼
- Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解
- SpringBoot整合SpringSecurity和JWT和Redis實(shí)現(xiàn)統(tǒng)一鑒權(quán)認(rèn)證
- SpringBoot使用Jwt處理跨域認(rèn)證問(wèn)題的教程詳解
- 詳解SpringBoot如何使用JWT實(shí)現(xiàn)身份認(rèn)證和授權(quán)
- 利用Springboot實(shí)現(xiàn)Jwt認(rèn)證的示例代碼
- springboot+jwt實(shí)現(xiàn)token登陸權(quán)限認(rèn)證的實(shí)現(xiàn)
- SpringBoot整合SpringSecurity實(shí)現(xiàn)JWT認(rèn)證的項(xiàng)目實(shí)踐
- Spring Boot整合JWT實(shí)現(xiàn)認(rèn)證與授權(quán)的項(xiàng)目實(shí)踐
相關(guān)文章
Mybatis-Plus自動(dòng)填充更新操作相關(guān)字段的實(shí)現(xiàn)
這篇文章主要介紹了Mybatis-Plus自動(dòng)填充更新操作相關(guān)字段的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
實(shí)例解析Java設(shè)計(jì)模式編程中的適配器模式使用
本篇文章主要通過(guò)實(shí)例對(duì)適配器模式進(jìn)行了詳解,需要的朋友可以參考下2017-04-04
詳解OpenCV For Java環(huán)境搭建與功能演示
這篇文章主要介紹了x詳解OpenCV For Java環(huán)境搭建與功能演示,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
java時(shí)間戳與日期相互轉(zhuǎn)換工具詳解
這篇文章主要為大家詳細(xì)介紹了java各種時(shí)間戳與日期之間相互轉(zhuǎn)換的工具,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
JavaWeb項(xiàng)目部署到服務(wù)器詳細(xì)步驟詳解
這篇文章主要介紹了JavaWeb項(xiàng)目如何部署到服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
java springmvc 注冊(cè)中央調(diào)度器代碼解析
這篇文章主要介紹了java springmvc 注冊(cè)中央調(diào)度器代碼解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Java創(chuàng)建內(nèi)部類對(duì)象實(shí)例詳解
這篇文章主要介紹了Java創(chuàng)建內(nèi)部類對(duì)象實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05

