【From】 http://blog.csdn.net/sun_t89/article/details/51923017html
Spring Boot實戰之Filter實現使用JWT進行接口認證java
jwt(json web token)web
用戶發送按照約定,向服務端發送 Header、Payload 和 Signature,幷包含認證信息(密碼),驗證經過後服務端返回一個token,以後用戶使用該token做爲登陸憑證,適合於移動端和apispring
jwt使用流程json

本文示例接上面幾篇文章中的代碼進行編寫,請閱讀本文的同時能夠參考前面幾篇文章api
一、添加依賴庫jjwt,本文中構造jwt及解析jwt都使用了jjwt庫app
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt</artifactId>
- <version>0.6.0</version>
- </dependency>
二、添加登陸獲取token時,所須要的認證信息類LoginPara.javaide
- 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;
- }
- }
三、添加構造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());
-
-
- JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
- .claim("role", role)
- .claim("unique_name", name)
- .claim("userid", userId)
- .setIssuer(issuer)
- .setAudience(audience)
- .signWith(signatureAlgorithm, signingKey);
-
- if (TTLMillis >= 0) {
- long expMillis = nowMillis + TTLMillis;
- Date exp = new Date(expMillis);
- builder.setExpiration(exp).setNotBefore(now);
- }
-
-
- return builder.compact();
- }
- }
四、添加token返回結果類AccessToken.javaui
- 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;
- }
- }
五、添加獲取token的接口,經過傳入用戶認證信息(用戶名、密碼)進行認證獲取
- 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;
- }
-
-
-
-
-
- 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;
- }
- }
-
-
- String accessToken = JwtHelper.createJWT(loginPara.getUserName(), String.valueOf(user.getName()),
- user.getRole(), audienceEntity.getClientId(), audienceEntity.getName(),
- audienceEntity.getExpiresSecond() * 1000, audienceEntity.getBase64Secret());
-
-
- 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;
- }
- }
- }
六、添加使用jwt認證的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 {
-
- SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
- filterConfig.getServletContext());
-
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
-
-
- 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() {
-
-
- }
- }
七、在入口處註冊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;
- }
- }
八、添加獲取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();
- }
- }
九、在返回信息類中補充添加錯誤碼
- 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");
十、代碼中涉及的Audience類,在上一篇文章中定義,本文再也不重複說明
十一、代碼總體結構

十二、測試
1) 獲取token,傳入用戶認證信息

認證經過返回token信息

2) 使用上面獲取的token進行接口調用
未使用token,獲取token錯誤,或者token過時時

使用正確的token時
