JWTTOKEN-先后端分离,springboot2结合JWTtoken

1.JWT简介java

        JSON Web Token(缩写 JWT),是目前最流行的跨域认证解决方案。web

2.JWT的原理spring

       JWT的原理是,服务器认证之后,生成一个JSON格式的对象,发回给客户端,就像下面这样.数据库

 

{
  "用户名": "admin",
  "角色": "超级管理员",
  "到期时间": "2019-07-13 00:00:00"
}

 

          之后,客户端与服务端通讯的时候,都要发回这个 JSON 对象。服务器彻底只靠这个对象认定用户身份。跨域

       为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。服务器

        服务器再也不保存任何 session 数据,也就是服务器变成无状态了,从而比较容易实现扩展。session

3.JWT的数据结构数据结构

        实际的 JWT是一个很长的字符串,中间用点(.)分隔成三个部分。 就像下面这样:app

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjNmMmc1N2E5MmFhIn0.eyJpYXQiOjE1NjI4MzM0MDgsImlzcyI6Imh0dHA6XC9cL3d3dy5weWcuY29tIiwiYXVkIjoiaHR0cDpcL1wvd3d3LnB5Zy5jb20iLCJuYmYiOjE1NjI4MzM0MDcsImV4cCI6MTU2MjkxOTgwOCwianRpIjoiM2YyZzU3YTkyYWEiLCJ1c2VyX2lkIjoxfQ.NFq1qQ-Z5c4pwit8ZkyWEwX6SBXmnHJcc6ZDgSD5nhU

          JWT的三个部分依次以下:ide

- Header(头部)
- Payload(负载)
- Signature(签名)

4.JWT的使用方式

             客户端收到服务器返回的 JWT,能够储存在 Cookie 里面,也能够储存在 localStorage。

此后,客户端每次与服务器通讯,都要带上这个 JWT。你能够把它放在 Cookie 里面自动发送,可是这样不能跨域,因此更好的作法是放在 HTTP 请求的头信息Authorization字段里面

5.JWT的几个特色

          (1)JWT 默认是不加密,但也是能够加密的。生成原始 Token 之后,能够用密钥再加密一次。

           (2)JWT 不加密的状况下,不能将秘密数据写入 JWT。

           (3)JWT 不只能够用于认证,也能够用于交换信息。有效使用 JWT,能够下降服务器查询数据库的次数。

           (4)JWT 的最大缺点是,因为服务器不保存 session 状态,所以没法在使用过程当中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期以前就会始终有效,除非服务器部署额外的逻辑。

           (5)JWT 自己包含了认证信息,一旦泄露,任何人均可以得到该令牌的全部权限。为了减小盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

           (6)为了减小盗用,JWT 不该该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

6.JWT功能实现

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

public class JwtHelper {
	// 秘钥
	static final String SECRET = "X-Token";
	// 签名由谁生成
	static final String ISSUSER = "WXW";
	// 签名的主题
	static final String SUBJECT = "this is my token";
	// 签名的观众
	static final String AUDIENCE = "MINAPP";
	
	
	public String createToken(Integer userId){
		try {
		    Algorithm algorithm = Algorithm.HMAC256(SECRET);
		    Map<String, Object> map = new HashMap<String, Object>();
		    Date nowDate = new Date();
		    // 过时时间:2小时
		    Date expireDate = getAfterDate(nowDate,0,0,0,2,0,0);
	        map.put("alg", "HS256");
	        map.put("typ", "JWT");
		    String token = JWT.create()
		    	// 设置头部信息 Header
		    	.withHeader(map)
		    	// 设置 载荷 Payload
		    	.withClaim("userId", userId)
		        .withIssuer(ISSUSER)
		        .withSubject(SUBJECT)
		        .withAudience(AUDIENCE)
		        // 生成签名的时间 
		        .withIssuedAt(nowDate)
		        // 签名过时的时间 
		        .withExpiresAt(expireDate)
		        // 签名 Signature
		        .sign(algorithm);
		    return token;
		} catch (JWTCreationException exception){
			exception.printStackTrace();
		}
		return null;
	}
	
	public Integer verifyTokenAndGetUserId(String token) {
		try {
		    Algorithm algorithm = Algorithm.HMAC256(SECRET);
		    JWTVerifier verifier = JWT.require(algorithm)
		        .withIssuer(ISSUSER)
		        .build();
		    DecodedJWT jwt = verifier.verify(token);
		    Map<String, Claim> claims = jwt.getClaims();
		    Claim claim = claims.get("userId");
		    return claim.asInt();
		} catch (JWTVerificationException exception){
//			exception.printStackTrace();
		}
		
		return 0;
	}
	
	public  Date getAfterDate(Date date, int year, int month, int day, int hour, int minute, int second){
		if(date == null){
			date = new Date();
		}
		
		Calendar cal = new GregorianCalendar();
		
		cal.setTime(date);
		if(year != 0){
			cal.add(Calendar.YEAR, year);
		}
		if(month != 0){
			cal.add(Calendar.MONTH, month);
		}
		if(day != 0){
			cal.add(Calendar.DATE, day);
		}
		if(hour != 0){
			cal.add(Calendar.HOUR_OF_DAY, hour);
		}
		if(minute != 0){
			cal.add(Calendar.MINUTE, minute);
		}
		if(second != 0){
			cal.add(Calendar.SECOND, second);
		}
		return cal.getTime();
	}
	
}

 

import org.linlinjava.litemall.wx.util.JwtHelper;

/**
 * token 管理
 */
public class UserTokenManager {
	public static String generateToken(Integer id) {
        JwtHelper jwtHelper = new JwtHelper();
        return jwtHelper.createToken(id);
    }
    public static Integer getUserId(String token) {
	    if( null == token ){
	        return null;
        }
    	JwtHelper jwtHelper = new JwtHelper();
		Integer userId = jwtHelper.verifyTokenAndGetUserId(token);
		if(userId == null || userId == 0){
			return null;
		}
		return userId;
    }

	public static void main(String[] args) {
		System.out.println(generateToken(9));
	}
}

 

使用

自定义参数解析器 

过程:  根据请求, 解析请求头中的token,得到到用户信息,将用户信息传递对应请求的method。

可查看原文: https://blog.csdn.net/sunshine_YG/article/details/85125373 

 

1.自定义注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {

}

2.解析类

import com.xxx.xx.LoginUser;
import com.xxx.xx.UserTokenManager;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;


public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    public static final String LOGIN_TOKEN_KEY = "X-Token";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().isAssignableFrom(Integer.class) && parameter.hasParameterAnnotation(LoginUser.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container,
                                  NativeWebRequest request, WebDataBinderFactory factory) throws Exception {

//        return new Integer(1);
        String token = request.getHeader(LOGIN_TOKEN_KEY);
        if (token == null || token.isEmpty()) {
            return null;
        }

        return UserTokenManager.getUserId(token);
    }
}

 

3.注册配置

import com.xxx.xx.xx.LoginUserHandlerMethodArgumentResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WxWebMvcConfiguration implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new LoginUserHandlerMethodArgumentResolver());
    }
// 拦截器
public void addInterceptors(InterceptorRegistry registry) {
        // 可设置拦截器
    }
}

 

4. 使用

import com.xxx.xxx.xxx.ResponseUtil; 
import com.xxx.xxx.xxx.LoginUser; 
import org.springframework.web.bind.annotation.*;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * index服务 
 */ 
@RestController
@RequestMapping("/index") 
public class IndexController {  

    
    @GetMapping("index")
    public Object index(@LoginUser Integer userId) {
        // 打印userId
        return ResponseUtil.ok(userId);
    }
}

 

5. postman请求i携带

 

获取完毕

相关文章
相关标签/搜索