User login authentication is Web A very common business in applications , The general process is like this :

  • The client sends the user name and password to the server
  • After the server-side verification passes , In the current session (session) Save relevant data in , For example, login time 、 Sign in IP etc. .
  • The server returns a... To the client session_id, The client saves it in Cookie in .
  • When the client sends a request to the server again , take session_id Send it back to the server .
  • On the server side session_id after , Identify the user .

In the case of a single machine , There is no problem with this model , But for front and rear end separation Web applications , It's very painful . So there is another solution , The server side will no longer save session data , Instead, save it on the client , Each time the client initiates a request, it sends the data to the server for verification .JWT(JSON Web Token) It is a typical representative of this scheme .

One 、 About JWT

JWT, It's the most popular Cross domain Certification solutions : The client initiates a user login request , After the server receives and authenticates successfully , Generate a JSON object ( As shown below ), And then it's returned to the client .

{
"sub": "wanger",
"created": 1645700436900,
"exp": 1646305236
}

When the client communicates with the server again , Put this JSON Take the object with you , As a certificate of mutual trust between the front and back ends . After the server receives the request , adopt JSON Object to authenticate the user , This eliminates the need to save any session Data. .

If I use a user name now wanger And password 123456 Access programming meow (Codingmore) Of login Interface , So practical JWT It's a string that looks like it's encrypted .

In order to let everyone see more clearly , I copied it to jwt Its official website .

left Encoded Part is JWT Ciphertext , Intermediate use 「.」 Divided into three parts ( On the right side Decoded part ):

  • Header( Head ), describe JWT Metadata , among alg The algorithm of attribute representation signature ( At present, it is HS512);
  • Payload( load ), It is used to store the data that needs to be transferred , among sub Property represents the subject ( The actual value is user name ),created Attribute representation JWT Time of birth ,exp Property indicates the expiration time
  • Signature( Signature ), Signature of the first two parts , Prevent data tampering ; You need to specify a key on the server side ( Only the server side knows ), Can't leak to client , And then use Header The signature algorithm specified in , Follow the formula below to generate a signature :
HMACSHA512(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)

After you figure out the signature , And then Header、Payload、Signature Concatenate into a string , Intermediate use 「.」 Division , You can return it to the client .

The client gets JWT after , Can be placed in localStorage, It can also be placed in Cookie Inside .

const TokenKey = '1D596CD8-8A20-4CEC-98DD-CDC12282D65C' // createUuid()

export function getToken () {
return Cookies.get(TokenKey)
} export function setToken (token) {
return Cookies.set(TokenKey, token)
}

When the client communicates with the server in the future , Just take this JWT, Generally placed on HTTP The header of the request Authorization In the field .

Authorization: Bearer <token>

After the server receives the request , Right again JWT To verify , If the verification is passed, the corresponding resources will be returned .

Two 、 actual combat JWT

First step , stay pom.xml Add... To the file JWT Dependence .

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>

The second step , stay application.yml Add JWT Configuration item for .

jwt:
tokenHeader: Authorization #JWT Stored request header
secret: codingmore-admin-secret #JWT The key used for encryption and decryption
expiration: 604800 #JWT Beyond the deadline of (60*60*24*7)
tokenHead: 'Bearer ' #JWT Get the beginning of the load

The third step , newly build JwtTokenUtil.java Tool class , There are three main ways :

  • generateToken(UserDetails userDetails): Generated according to the logged in user token
  • getUserNameFromToken(String token): from token Get login user
  • validateToken(String token, UserDetails userDetails): Judge token Whether it is still valid
public class JwtTokenUtil {

    @Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
@Value("${jwt.tokenHead}")
private String tokenHead; /**
* According to the user information token
*/
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
} /**
* According to the user name 、 Create time generation JWT Of token
*/
private String generateToken(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims)
.setExpiration(generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
} /**
* from token Get login user name
*/
public String getUserNameFromToken(String token) {
String username = null;
Claims claims = getClaimsFromToken(token);
if (claims != null) {
username = claims.getSubject();
} return username;
} /**
* from token In order to get JWT Load in
*/
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
LOGGER.info("JWT Format validation failed :{}", token);
}
return claims;
} /**
* verification token Is it still valid
*
* @param token From the client token
* @param userDetails User information from the database
*/
public boolean validateToken(String token, UserDetails userDetails) {
String username = getUserNameFromToken(token);
return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
} /**
* Judge token Is it invalid
*/
private boolean isTokenExpired(String token) {
Date expiredDate = getExpiredDateFromToken(token);
return expiredDate.before(new Date());
} /**
* from token Get the expiration time in the
*/
private Date getExpiredDateFromToken(String token) {
Claims claims = getClaimsFromToken(token);
return claims.getExpiration();
}
}

Step four , stay UsersController.java Newly added login Login interface , Receive user name and password , And will JWT Return to the client .

@Controller
@Api(tags=" user ")
@RequestMapping("/users")
public class UsersController {
@Autowired
private IUsersService usersService;
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead; @ApiOperation(value = " Log in and return to token")
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public ResultObject login(@Validated UsersLoginParam users, BindingResult result) {
String token = usersService.login(users.getUserLogin(), users.getUserPass()); if (token == null) {
return ResultObject.validateFailed(" Wrong user name or password ");
} // take JWT Pass back to the client
Map<String, String> tokenMap = new HashMap<>();
tokenMap.put("token", token);
tokenMap.put("tokenHead", tokenHead);
return ResultObject.success(tokenMap);
} }

Step five , stay UsersServiceImpl.java Newly added login Method , Query the user from the database according to the user name , Generate after password verification JWT.

@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements IUsersService { @Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private JwtTokenUtil jwtTokenUtil; public String login(String username, String password) {
String token = null;
// The password needs to be passed after being encrypted by the client
try {
// Query the user + User resources
UserDetails userDetails = loadUserByUsername(username); // Verify password
if (!passwordEncoder.matches(password, userDetails.getPassword())) {
Asserts.fail(" Incorrect password ");
} // return JWT
token = jwtTokenUtil.generateToken(userDetails);
} catch (AuthenticationException e) {
LOGGER.warn(" Login exception :{}", e.getMessage());
}
return token;
}
}

Step six , newly added JwtAuthenticationTokenFilter.java, Every time the client makes a request, it will respond to JWT To verify .

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead; @Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
// Get... From the client request JWT
String authHeader = request.getHeader(this.tokenHeader);
// The JWT It's the format we stipulated , With tokenHead start
if (authHeader != null && authHeader.startsWith(this.tokenHead)) {
// The part after "Bearer "
String authToken = authHeader.substring(this.tokenHead.length());
// from JWT Get user name
String username = jwtTokenUtil.getUserNameFromToken(authToken);
LOGGER.info("checking username:{}", username); // SecurityContextHolder yes SpringSecurity A tool class of
// Save the security context of the current user in the application
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// Obtain login user information according to user name
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
// verification token Is it overdue
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
// Save the logged in user in a security context
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication); LOGGER.info("authenticated user:{}", username);
}
}
}
chain.doFilter(request, response);
}
}

JwtAuthenticationTokenFilter Inherited OncePerRequestFilter, This filter ensures that a request passes only once filter, It doesn't need to be repeated . in other words , Every time the client initiates a request , The filter will execute once .

This filter is very critical , Basically, I added comments to every line of code , Yes, of course , To make sure everyone can figure out what this class does , Let me draw another flow chart , So it's clear .

SpringSecurity Is a security management framework , You can talk to Spring Boot Application seamless connection ,SecurityContextHolder Is one of the key tool classes , Hold security context information , Who is the user who saves the current operation , Whether the user has been authenticated , Key information such as permissions owned by users .

SecurityContextHolder Default used ThreadLocal Policies to store authentication information ,ThreadLocal It's characterized by the data in it , Which thread has stored , Which thread can access . This means that after different requests enter the server , There will be different Thread To deal with , For example, threads A The request 1 User information is stored in ThreadLocal, Threads B Processing request 2 You can't get the user's information when you are .

So JwtAuthenticationTokenFilter The filter will do it every time a request comes JWT Validation of the , Ensure that the request from the client is secure . then SpringSecurity The next request interface will be released . This is also JWT and Session Fundamental difference :

  • JWT You need to verify every request , And as long as JWT No expired , Even if the server is restarted , The certification is still valid .
  • Session Without expiration, it is not necessary to re verify the user information , When the server is restarted , The user needs to log in again to get a new Session.

in other words , stay JWT Under the scheme of , The key saved on the server side (secret) We must not divulge , Otherwise, the client can forge the user's authentication information according to the signature algorithm .

3、 ... and 、Swagger Add JWT verification

For back-end developers , How to be in Swagger( Integrated Knife4j Beautify ) Add JWT What about verification ?

First step , visit login Interface , Enter your user name and password to log in , Get the information returned by the server JWT.

The second step , Collect the data returned by the server tokenHead and token, Fill it in Authorize( Be careful tokenHead and token There is a space between ) Complete login authentication .

The third step , When another interface is requested ,Swagger Will automatically Authorization Send it to the server as request header information .

Step four , After the server receives the request , Will pass JwtAuthenticationTokenFilter Filter right JWT check .

Only this and nothing more , The whole process has been opened up , perfect !

Four 、 summary

To sum up , use JWT To solve the cross domain authentication in the front and rear end separation project is very smooth , This is mainly due to JSON The generality of , Can cross language ,JavaScript and Java All support ; in addition ,JWT The composition of is very simple , Very easy to transmit ; also JWT There is no need to save session information on the server side (Session), Very easy to expand .

Yes, of course , In order to ensure JWT The security of , Not in JWT Save sensitive information in , Because once the private key is compromised ,JWT It is easy to decrypt on the client ; If possible , Please use HTTPS agreement .

Reference link :

Ruan Yifeng :https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

Spring, summer, autumn and winter :https://segmentfault.com/a/1190000012557493

A little rain in Jiangnan :https://cloud.tencent.com/developer/article/1612175

Dearmadman:https://www.jianshu.com/p/576dbf44b2ae

mcarozheng:http://www.macrozheng.com/

Source path :

https://github.com/itwanger/coding-more


This article has been included in GitHub On the star 1.6k+ star Open source column 《Java The road to advancement of programmers 》, It is said that every excellent Java Programmers like her , Humor and wit humor 、 Easy to understand . The content includes Java Basics 、Java Concurrent programming 、Java virtual machine 、Java Enterprise development 、Java Interview and other core knowledge points . learn Java, Just recognize it Java The road to advancement of programmers .

https://github.com/itwanger/toBeBetterJavaer

star Having this warehouse means that you have become an excellent Java The potential of Engineers . You can also stamp the link below to jump to 《Java The road to advancement of programmers 》 The official website of , Start a pleasant learning journey .

https://tobebetterjavaer.com/

Nothing makes me stay —— Except for the purpose , Even if there are roses by the shore 、 There's shade 、 There is a peaceful harbor , I'm not a boat .

kill Session? This cross domain authentication solution is really elegant ! More articles about

  1. JSON Web Token( abbreviation JWT) At present, the most popular cross domain authentication solution

    One . The problem of cross domain authentication Internet service can not do without user authentication . The general process is as follows . 1. The user sends the user name and password to the server . 2. After the server is verified , In the current conversation (session) It holds relevant data , For example, user roles . Login time and so on . ...

  2. JWT token Cross domain authentication

    JSON Web Token( abbreviation JWT), Is the most popular cross domain authentication solution . session Login authentication scheme : The user passes the user name from the client . Password and other information , After authentication, the server stores the information in session in , take sessio ...

  3. angularjs Cross domain post Solution

    from :http://www.thinksaas.cn/topics/0/34/34536.html Li Lei, a front-end classmate, and Hanmeimei, a back-end classmate, developed on their own computers , When the background interface is written , Li Lei uploads the front-end code after making changes ...

  4. C# Advanced Series ——WebApi Cross domain problem solution :CORS

    Preface : The first part summarizes WebApi The use of interface testing tools , Let's take a look at this article WebAPI Another common problem with : Cross-domain problem . This article mainly from the perspective of examples to share CORS Some details of solving cross domain problems . WebApi Series articles C# Advanced Series — ...

  5. thinkphp,javascript Cross domain request solution

    javascript Cross domain request solution Preface For many front-end or mixed development students , We will inevitably encounter cross domain request services , such as A Site to B The site requests data and so on . Recently, I will do a site cluster project , So the specific business requires many sites ...

  6. C# Advanced Series ——WebApi Cross domain problem solution :CORS( Reprint )

    C# Advanced Series ——WebApi Cross domain problem solution :CORS   Read the directory One . The origin of cross domain problems Two . Cross domain problem solving principles 3、 ... and . Cross domain problem solving details 1. Scene description 2. Scenario test Four . summary Text Preface : The first part summarizes W ...

  7. Cross domain learning notes 2--WebApi Cross domain problem solution :CORS

    I don't know , Let's record it here , It's for later study ... Text Preface : The first part summarizes WebApi The use of interface testing tools , Let's take a look at this article WebAPI Another common problem with : Cross-domain problem . This article mainly from the perspective of examples to share CORS Solve cross ...

  8. jquery Cross domain access solutions ( turn )

    client “ Cross domain access ” It's always been a headache , Fortunately, there are jQuery Help , from jQuery-1.2 In the future, cross domain problems will be solved . Because I encountered cross domain problems in the project , Take this opportunity to get to the bottom of cross domain issues , Consult the relevant information and my own practice , count ...

  9. localstrage、cookie、session And other cross domain and cross page monitoring update issues

    localstrage.cookie.session And other cross domain and cross page monitoring update issues

  10. cors Cross domain and jsonp Hijacking loopholes and Same origin policy and cross domain request solution

    cors Cross domain and jsonp Hijacking loopholes : https://www.toutiao.com/a6759064986984645127/ Same origin policy and cross domain request solution :https://www.jianshu.co ...

Random recommendation

  1. mongodb Common commands

    mongodb Common commands Operation on Database , And login 1 Access to database use admin 2 Add or change password db.addUser('wsc', '123') 3 View the list of users db.system.us ...

  2. Head First Strategic patterns of design patterns

    This is the first design pattern to learn , The examples in the book are relatively complex , Reference to the online article to summarize One . Definition The strategy pattern (strategy pattern): The algorithm family is defined , Close them separately , Let's make them interchangeable , This module ...

  3. angular4 upgrade angular5 Problem record this.location.back()

    In previous projects , Navigate back to the last route using injected Location service , Use the browser's history stack , Navigate to the previous step . That's what the official documents say However, it is upgrading to 5.2 In the version of , There is no problem when the browser is running , Print in the project ...

  4. With cute new look springboot Source code 03

    The last section talked about quickly creating a new springboot application , as well as springboot When the autoconfiguration class works , And looked at the source code of an automatic configuration class . In this section, let's take a rough look at when a user enters a url, How to return a ...

  5. after RCNN The development of object detection and instance segmentation

    https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&mid=2650736740&idx=3&sn=cdce446703e69b ...

  6. 4~20mA

    4~20mA Current output chip XTR111 Complete circuit 0-5v turn 0-20ma and 0-5v turn 4-20ma Voltage controlled constant current source circuit 4-20mA Introduction to current loop transmitter

  7. Ioc:Autofac Registration Concepts

    Reflection Components When using reflection-based components, Autofac automatically uses the constru ...

  8. Windows Phone 8.1 Update Preview backup The solution to failure

    We are currently using the developer preview (8.10.14219.341), I haven't been able to back it up lately text + apps + settings, The progress bar reaches 97% or 99% I'll tell you later : There was a problem ba ...

  9. Algorithm --- This is a summary 2—— Find the missing number , Find the biggest and the smallest , front k Big , The first k Small number

    One . How to find the missing number in the array Title Description : Given a by n-1 An unordered array of integers , The original is 1 To n Different integers in , Please write a linear time algorithm to find the missing integers in the array sequence Method 1: Sum by accumulation The time complexity is O(N ...

  10. Sqlserver Generate scripts with data

    Right click the database —> Mission —> Generation script next step Select the database to export , next step Write a data script to choose True, next step Select the table to export , next step Finally, click finish .