JWT's official website: https://jwt.io/
JWT (the Java version) of github Address: https://github.com/jwtk/jjwt
What is the JWT
Web token JSON (the JWT) , is based on the statement to transfer between the network environment and the execution of JSON
open standards ((RFC 7519). Definition of a compact, self-contained method for communication between parties to JSON
the object transmission of information in the form of security. because there is a digital signature, the information is credible, the JWT can use the HMAC
algorithm or the RSA
public and private keys to sign.
JWT request process
image.png
1. The user account and the surface of the post request issued;
2. server using a private key to create a jwt;
3. jwt the server returns to the browser;
4. The browser sends a request string jwt image server in the request header;
5. the authentication server JWT;
6. the resource response returned to the browser.
JWT's main scenario
Authentication In this scenario, once the user has completed the landing, JWT included in each of the next request, it can be used to authenticate users as well as access to routes, services and resources for verification. Because of its overhead is very small, you can easily transfer system different domain names, all currently in the single sign-on (SSO) in more extensive use of the technology. Exchange of information between the parties to communicate using JWT data coding is a very safe way, because it is a signed message, the sender can ensure that information is not transmitted through forged.
advantage
1. Concise (Compact): can URL
, POST
parameters or HTTP header
transmission, because of the small amount of data, transmission speed is fast
2. The self-contained (Self-contained): it contains information about all the load required by the user, avoiding multiple query the database
3. because Token
is JSON
encrypted form stored in the client, it JWT
is cross-language, any web form in principle support.
4. no need to store session information on the server side, particularly for distributed micro service.
`
JWT structure
JWT is composed of three pieces of information, these three pieces of information with a text link together constitute JWT string.
like this:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
JWT consists of three components:
Header header (header contains metadata token, and contains the type signature and / or encryption algorithms)
Payload load (like article carried on an airplane)
the Signature Signature / visa
Header
JWT head carries two pieces of information: token and type of encryption algorithm.
{
"alg": "HS256",
"typ": "JWT"
}
Statement type: Here is jwt
assertion of the encryption algorithm: usually used as HMAC SHA256
Encryption algorithm is a one-way hash function algorithm, a common MD5, SHA, HAMC.
The MD5 (Message-Digest algorithm. 5) (Information - digest algorithm) abbreviations widely used in encryption and decryption techniques commonly used in the file verification. check? No matter how big the file, after MD5 can generate a unique MD5 value of
SHA (Secure Hash Algorithm, Secure Hash Algorithm) , digital signatures and other cryptographic applications important tool in safe MD5
HMAC (Hash the Message Authentication Code) , hash message authentication code, the authentication protocol hash algorithm key. A fixed-length value generated using the public key as a function of authentication and identification, with this identity authentication message integrity. Commonly used in the interface signature verification
Payload
Load local storage is valid information.
Effective information consists of three parts
STATEMENT 1. standard registered
2. Public Statement
3. Statement private
Standard registration statement (recommended, but not mandatory to use):
iss
: Jwt Issuer sub
: user-facing (facing the user jwt) aud
: one receiving jwt of exp
: expiration timestamps (jwt expiration time, the expiration time must be greater than the time of issue) nbf
: Definitions Before what time, which are jwt not available. iat
: jwt the issue of time jti
: jwt unique identity, is mainly used as a one-off token
, so avoid replay attacks.
Public statement:
Public declarations can add any information, general information about the user to add the necessary information or other business needs, but is not recommended for sensitive information to add, in part because the client can decrypt.
Private statement:
Private statement is a statement providers and consumers as common definition, is generally not recommended to store sensitive information, as base64
is decrypted symmetric, meaning that some of the information may be classified as plaintext.
Signature
The third part is a jwt visa information, the visa information consists of three parts:
header (after Base64)
payload (after Base64)
Secret
This section requires base64
encrypted header
and base64
encrypted payload
using the .
strings are connected, then header
encrypted manner declared salt secret
composition encryption, and constitutes jwt
a third portion.
The key secret
is stored on the server, the server will be generated from this key token
and validate, so they need to protect.
Let's integrate SpringBoot and the JWT
Introducing JWT
dependence, because it is based Java
, it is necessary thatjava-jwt
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
You need to customize two notes
Used to skip verificationPassToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
boolean required() default true;
}
Login required to operate commentUserLoginToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
boolean required() default true;
}
@Target
: The role of the target annotation
@Target(ElementType.TYPE)
- interfaces, classes, enumerations, annotations @Target(ElementType.FIELD)
- field, enumeration constants @Target(ElementType.METHOD)
- Method @Target(ElementType.PARAMETER)
- Method Parameter @Target(ElementType.CONSTRUCTOR)
- Constructor @Target(ElementType.LOCAL_VARIABLE)
- Local variables @Target(ElementType.ANNOTATION_TYPE)
- annotations @Target(ElementType.PACKAGE)
- package
@Retention
: Annotation reserved position
RetentionPolicy.SOURCE
: This type of Annotations
the source code level only retained, it will be ignored by the compiler when the class
not contain bytecode file. RetentionPolicy.CLASS
: This type Annotations
is reserved by the compiler, the default retention policy, in class
the presence of the file, but JVM
will be ignored, can not get running. RetentionPolicy.RUNTIME
: This type Annotations
will be JVM
retained, so that they can be run in JVM
the read and use or other uses reflection code. @Document
: Indicates that the annotation will be included in javadoc
the @Inherited
: description subclasses inherit the parent class annotation
A simple custom entity class User
, using the lombok
write simplified entity class
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
String Id;
String username;
String password;
}
You need to write token
the Generation
public String getToken(User user) {
String token="";
token= JWT.create().withAudience(user.getId())
.sign(Algorithm.HMAC256(user.getPassword()));
return token;
}
Algorithm.HMAC256()
: Use HS256
generated token
key is the user's password, unique key, then can be saved on the server. withAudience()
Deposit needs to be saved in token
the information, here I put the user ID
into token
the
Next you need to write an interceptor to obtain token
and verifytoken
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
// 如果不是映射到方法直接通过
if(!(object instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod=(HandlerMethod)object;
Method method=handlerMethod.getMethod();
//检查是否有passtoken注释,有则跳过认证
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
return true;
}
}
//检查有没有需要用户权限的注解
if (method.isAnnotationPresent(UserLoginToken.class)) {
UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
if (userLoginToken.required()) {
// 执行认证
if (token == null) {
throw new RuntimeException("无token,请重新登录");
}
// 获取 token 中的 user id
String userId;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("401");
}
User user = userService.findUserById(userId);
if (user == null) {
throw new RuntimeException("用户不存在,请重新登录");
}
// 验证 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("401");
}
return true;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
Implement a interceptor need to implement HandlerInterceptor
the interface
HandlerInterceptor
Main interface defines three methods
1 boolean preHandle ()
:
Pretreatment callback method, to achieve the pre-processor, in response to the third parameter processor, custom Controller
, the return value true
represents a continuing process (e.g., a call to the next process or interceptors device) or followed by execution postHandle()
and afterCompletion()
; false
flowchart showing an interrupt, will not continue to call other interceptors or processor, interrupt execution.
2 void postHandle()
:
After processing the callback method to achieve post-processing processor ( DispatcherServlet
Called before a return to a view rendering), then we can modelAndView
process the data model (model and view objects) or to view processed modelAndView
also may be null
.
3 void afterCompletion()
:
the whole callback request is processed, the method also requires a current corresponding Interceptor
to preHandle()
only executes if the return value is true, i.e. the DispatcherServlet
rendering corresponding view after execution. For resource cleanup. Complete request a callback method is completed. Such as performance monitoring, we can end this record time and outputs time-consuming, it can also clean up some resources, like try-catch-finally
in finally
, but only call processor execution chain
The main processes:
1. From the http
Remove request header token
,
2. a method for mapping determines whether
3. Check passtoken
Notes, there are skip authentication
4. There is no need to check the annotation user login, and verify that there is the need to remove
5. authentication can access, not by the relevant error message will be reported
Configuring interceptors
In the configuration class annotations added @Configuration
, marked with a class is configured as a class of that class and SpringBean
added to IOC
the vessel
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
WebMvcConfigurerAdapter
The abstract class in fact there is no way to achieve, just empty implements the interface WebMvcConfigurer
all methods within and did not give any business logic processing, which is designed just right so that we do not have to implement those we do not, we have handed over WebMvcConfigurerAdapter
abstract space-realization, if we need to make a logical process for a specific method, only need to WebMvcConfigurerAdapter
subclass @Override
the corresponding method on it.
NOTE:
In SpringBoot2.0
and Spring 5.0
of WebMvcConfigurerAdapter
already abandoned
the Internet has changed to inherit said WebMvcConfigurationSupport
, but the next test, or expired
Solution:
Direct implementation of WebMvcConfigurer
(the official recommended)
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
InterceptorRegistry
In addInterceptor
need an implementation of HandlerInterceptor
the interface interceptor instance, addPathPatterns
a method is provided for filtering path rules interceptor.
Here I intercept all requests, by determining whether there are @LoginRequired
annotations decide whether you need to log
Join Login operate annotation data access interface
@RestController
@RequestMapping("api")
public class UserApi {
@Autowired
UserService userService;
@Autowired
TokenService tokenService;
//登录
@PostMapping("/login")
public Object login(@RequestBody User user){
JSONObject jsonObject=new JSONObject();
User userForBase=userService.findByUsername(user);
if(userForBase==null){
jsonObject.put("message","登录失败,用户不存在");
return jsonObject;
}else {
if (!userForBase.getPassword().equals(user.getPassword())){
jsonObject.put("message","登录失败,密码错误");
return jsonObject;
}else {
String token = tokenService.getToken(userForBase);
jsonObject.put("token", token);
jsonObject.put("user", userForBase);
return jsonObject;
}
}
}
@UserLoginToken
@GetMapping("/getMessage")
public String getMessage(){
return "你已通过验证";
}
}
Without comment, then no default authentication, the interface is generally not verified. In getMessage()
I add a comment login, indicates that this interface must be logged obtain token
after, plus the request header token
and can only be accessed by verified
The following test, start the project, using the postman test interface
In no token
access in the case of api/getMessage
an interface
image.png
I here use a unified exception handling, so only see an errormessage
Below to log in, in order to gaintoken
image.png
Log In verification operation I did not add annotations, so you can directly access
The token
increase in the request header, again access api/getMessage
interfaces
image.png
Note: This key
must not be wrong, because the interceptor is key to take token
the value of String token = httpServletRequest.getHeader("token");
adding token
after which you can pass the authentication and access interface
github project Source Address: https://github.com/JinBinPeng/springboot-jwt
Original Address: https://www.jianshu.com/p/e88d3f8151db