当前位置:网站首页>JWT login authentication + token automatic renewal scheme, well written!
JWT login authentication + token automatic renewal scheme, well written!
2022-07-28 11:16:00 【Java technology stack】
author : Is he Tiantian here
link :https://juejin.cn/post/6932702419344162823
In the past, I was mainly responsible for the user management module in the project , The user management module will involve encryption and authentication processes , Encryption has been introduced in the previous article , You can read the user management module : How to ensure user data security .
Today, let's talk about the technical selection and implementation of authentication function . There is no technical difficulty, and of course there is no challenge , But it is also a kind of exercise for a vegetable chicken sweet that has not written the certification function before
Technology selection
To realize the authentication function , It's easy to think of JWT perhaps session, But what's the difference between the two ? Advantages and disadvantages of each ? should Pick who ? Deadly third company
difference
be based on session And based on JWT The main difference is where the user's state is saved ,session It's stored in the server Of , and JWT It's saved on the client side Of
The certification process
be based on session The authentication process of
- The user enters the user name and password in the browser , The server generates a password after passing the password verification session And save to database
- The server generates a for the user sessionId, And will have sesssionId Of cookie Place in user browser , This will be included in subsequent requests cookie Access information
- Server acquisition cookie, By acquiring cookie Medium sessionId Search the database to determine whether the current request is valid
be based on JWT The authentication process of
- The user enters the user name and password in the browser , The server generates a password after passing the password verification token And save to database
- The front end gets token, Store in cookie perhaps local storage in , This will be included in subsequent requests token Access information
- Server acquisition token value , By looking up the database to determine the current token Whether it works
Advantages and disadvantages
- JWT Save on client , In a distributed environment, no extra work is required . and session Because it is saved on the server side , It is necessary to realize multi machine data sharing in distributed environment
- session It usually needs to be combined with Cookie Achieve Authentication , So you need browser support cookie, Therefore, the mobile terminal cannot be used session Certification scheme
Security
- JWT Of payload It uses base64 Coded , So in JWT You can't store sensitive data in . and session The information of is stored in the server , Relatively safer
If in JWT Sensitive information is stored in , It can be decoded, which is very unsafe
performance
- After coding JWT Will be very long ,cookie The size of the limit is generally 4k,cookie It's very likely that I can't put , therefore JWT Generally placed on local storage Inside . And every time the user is in the system http Requests will bring JWT Carry in Header Inside ,HTTP Requested Header Maybe it's better than Body Even bigger . and sessionId It's just a very short string , Therefore use JWT Of HTTP Request is better than use session It's a lot more expensive
Disposable
Stateless is JWT Characteristics , But it also leads to this problem ,JWT It's disposable . I want to modify the contents , You have to issue a new JWT
- It can't be abandoned Once a JWT, It will remain in effect until it expires , You can't abandon it . If you want to abandon , A common treatment is to combine redis
- Renewal If you use JWT Do conversation management , Conventional cookie Renewal programs are usually built into the framework ,session The period of validity 30 minute ,30 If there is an interview within minutes , The validity period is refreshed to 30 minute . The same thing , To change the JWT Effective time of , It's about to issue a new JWT. The simplest way is to refresh every time you request JWT, each HTTP All requests return a new JWT. This method is not only violent but also not elegant , And every request has to be made JWT Encryption and decryption of , Performance issues . Another way is to redis For each JWT Set expiration time , Refresh on every visit JWT The expiration time of
choice JWT or session
I vote for JWT One vote ,JWT There are many disadvantages , But in a distributed environment, you don't need to be like session As an additional implementation of multi machine data sharing , although seesion Multi machine data sharing can be achieved through viscosity session、session share 、session Copy 、 Persistence session、terracoa Realization seesion Copy And other mature solutions to solve this problem . however JWT No extra work required , Use JWT Is it not fragrant ? And JWT The disadvantages of one-off can be combined with redis Make up for . Improve the strength and make up the weakness , Therefore, in the actual project, we choose to use JWT To authenticate
Function realization
JWT The required depend on
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version></dependency>JWT Tool class
public class JWTUtil { private static final Logger logger = LoggerFactory.getLogger(JWTUtil.class); // Private key private static final String TOKEN_SECRET = "123456"; /** * Generate token, Custom expiration time millisecond * * @param userTokenDTO * @return */ public static String generateToken(UserTokenDTO userTokenDTO) { try { // Private key and encryption algorithm Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); // Set header information Map<String, Object> header = new HashMap<>(2); header.put("Type", "Jwt"); header.put("alg", "HS256"); return JWT.create() .withHeader(header) .withClaim("token", JSONObject.toJSONString(userTokenDTO)) //.withExpiresAt(date) .sign(algorithm); } catch (Exception e) { logger.error("generate token occur error, error is:{}", e); return null; } } /** * test token Whether it is right * * @param token * @return */ public static UserTokenDTO parseToken(String token) { Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); JWTVerifier verifier = JWT.require(algorithm).build(); DecodedJWT jwt = verifier.verify(token); String tokenInfo = jwt.getClaim("token").asString(); return JSON.parseObject(tokenInfo, UserTokenDTO.class); }}explain :
- Generated token There is no expiration time in the ,token The expiration time of is determined by redis Conduct management
- UserTokenDTO There is no sensitive information in the , Such as password The field will not appear in token in
Redis Tool class
public final class RedisServiceImpl implements RedisService { /** * Expiration time */ private final Long DURATION = 1 * 24 * 60 * 60 * 1000L; @Resource private RedisTemplate redisTemplate; private ValueOperations<String, String> valueOperations; @PostConstruct public void init() { RedisSerializer redisSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(redisSerializer); redisTemplate.setValueSerializer(redisSerializer); redisTemplate.setHashKeySerializer(redisSerializer); redisTemplate.setHashValueSerializer(redisSerializer); valueOperations = redisTemplate.opsForValue(); } @Override public void set(String key, String value) { valueOperations.set(key, value, DURATION, TimeUnit.MILLISECONDS); log.info("key={}, value is: {} into redis cache", key, value); } @Override public String get(String key) { String redisValue = valueOperations.get(key); log.info("get from redis, value is: {}", redisValue); return redisValue; } @Override public boolean delete(String key) { boolean result = redisTemplate.delete(key); log.info("delete from redis, key is: {}", key); return result; } @Override public Long getExpireTime(String key) { return valueOperations.getOperations().getExpire(key); }}RedisTemplate Simple packaging
Business implementation
Landing function
public String login(LoginUserVO loginUserVO) { //1. Determine whether the user name and password are correct UserPO userPO = userMapper.getByUsername(loginUserVO.getUsername()); if (userPO == null) { throw new UserException(ErrorCodeEnum.TNP1001001); } if (!loginUserVO.getPassword().equals(userPO.getPassword())) { throw new UserException(ErrorCodeEnum.TNP1001002); } //2. The user name and password are generated correctly token UserTokenDTO userTokenDTO = new UserTokenDTO(); PropertiesUtil.copyProperties(userTokenDTO, loginUserVO); userTokenDTO.setId(userPO.getId()); userTokenDTO.setGmtCreate(System.currentTimeMillis()); String token = JWTUtil.generateToken(userTokenDTO); //3. Deposit in token to redis redisService.set(userPO.getId(), token); return token;}explain :
- Determine whether the user name and password are correct
- If the user name and password are correct, generate token
- The generated token Save to redis
Logout function
public boolean loginOut(String id) { boolean result = redisService.delete(id); if (!redisService.delete(id)) { throw new UserException(ErrorCodeEnum.TNP1001003); } return result;}The corresponding key Delete it
Update password function
public String updatePassword(UpdatePasswordUserVO updatePasswordUserVO) { //1. Change Password UserPO userPO = UserPO.builder().password(updatePasswordUserVO.getPassword()) .id(updatePasswordUserVO.getId()) .build(); UserPO user = userMapper.getById(updatePasswordUserVO.getId()); if (user == null) { throw new UserException(ErrorCodeEnum.TNP1001001); } if (userMapper.updatePassword(userPO) != 1) { throw new UserException(ErrorCodeEnum.TNP1001005); } //2. Generate a new token UserTokenDTO userTokenDTO = UserTokenDTO.builder() .id(updatePasswordUserVO.getId()) .username(user.getUsername()) .gmtCreate(System.currentTimeMillis()).build(); String token = JWTUtil.generateToken(userTokenDTO); //3. to update token redisService.set(user.getId(), token); return token;}explain : A new password needs to be regenerated when updating the user password token, And new token Back to the front end , The front-end update is saved in local storage Medium token, At the same time, the update is stored in redis Medium token, This implementation can prevent users from logging in again , The user experience is not too bad
Other instructions
- In the actual project , Users are divided into ordinary users and administrator users , Only the administrator user has the right to delete users , This function also involves token Operation of the , But I'm too lazy ,demo The project will not be written
- In the actual project , Password transmission is encrypted
Interceptor class
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String authToken = request.getHeader("Authorization"); String token = authToken.substring("Bearer".length() + 1).trim(); UserTokenDTO userTokenDTO = JWTUtil.parseToken(token); //1. Determine if the request is valid if (redisService.get(userTokenDTO.getId()) == null || !redisService.get(userTokenDTO.getId()).equals(token)) { return false; } //2. Decide whether to renew if (redisService.getExpireTime(userTokenDTO.getId()) < 1 * 60 * 30) { redisService.set(userTokenDTO.getId(), token); log.error("update token info, id is:{}, user info is:{}", userTokenDTO.getId(), token); } return true;}explain : The interceptor mainly does two things , One is right token check , Second, judgment token Whether renewal is required token check :
- Judge id Corresponding token Does it not exist , Nonexistence token Be overdue
- if token Existence is more token Is it consistent , Ensure that only one user operates at the same time
token Automatic renewal : In order to operate infrequently redis, Only when the expiration time is only 30 The expiration time is updated in minutes
Interceptor configuration class
@Configurationpublic class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authenticateInterceptor()) .excludePathPatterns("/logout/**") .excludePathPatterns("/login/**") .addPathPatterns("/**"); } @Bean public AuthenticateInterceptor authenticateInterceptor() { return new AuthenticateInterceptor(); }}At the end
If there are mistakes and deficiencies , Welcome to point out
Recent hot article recommends :
1.1,000+ Avenue Java Arrangement of interview questions and answers (2022 The latest version )
2. Explode !Java Xie Cheng is coming ...
3.Spring Boot 2.x course , It's too complete !
4. Don't write about the explosion on the screen , Try decorator mode , This is the elegant way !!
5.《Java Development Manual ( Song Mountain version )》 The latest release , Download it quickly !
I think it's good , Don't forget to like it + Forward !
边栏推荐
- 国内外优秀程序员的博客全在这了,请查收
- Nodejs: detect and install the NPM module. If it is already installed, skip
- CTF skill tree - file upload
- 表格数据处理软件,除了Excel还有什么?
- JSON初步理解
- 使用statement对象执行DDL语句创建表
- Bc35 NB module at instruction development summary
- Tree shaking and DCE
- Here is a super practical excel shortcut set (common + summary of eight categories)
- 构建快捷开发IDE:VisualSVN+Sublime+Visual Studio 2013+QuickEasyFTPServer
猜你喜欢

The 10th Landbridge cup embedded electronic provincial competition

BC35 NB模块AT指令开发总结

Do data analysis, do you still not understand RFM analysis method (model)?

学会使用MySQL的Explain执行计划,SQL性能调优从此不再困难

21. Merge two ordered linked lists

I use the applet container to improve the efficiency of mobile R & D by 5 times!

Why is low code (apaas) popular again recently?

Sword finger offer 06. print linked list from end to end

float浮动初步理解

盘点:144个免费学习网站,全网最全资源合集
随机推荐
Reading these six books makes learning MySQL easier
内存操作函数memcpy()和memmove()的用法
offsetof宏与container_of宏分析详解
几个数据库的相关概念
Nodejs: set up the express service, set up the session and realize the exit operation
Problems needing attention when VC links static libraries
Blue Bridge Cup embedded Hal library systick
The solution of PHP sending mobile MAS SMS garbled code
Samba learning
ThinkPad指纹验证在win7无法使用的解决方法
Fhwy workday schedule
Under the platform driven platform, the "dev- > dev.of_node" of the formal parameter dev in the probe function Understanding of
蓝桥杯嵌入式-HAL库-USART_TX
【MySQL从入门到精通】【高级篇】(十)MyISAM的索引方案&&索引的优缺点
Sword finger offer 06. print linked list from end to end
Select without the order by clause, the order of the returned results is not reliable
The Xiongguan pass is like an iron road, and now we are going to cross it from the beginning
Nodejs: detect and install the NPM module. If it is already installed, skip
Invalid ROM Table原因及解决办法
一文学会如何做电商数据分析(附运营分析指标框架)