Use Sa-Token to complete login authentication under the front-end and back-end separation architecture

1. Architecture analysis

At present, most systems have been designed with a "separation of front-end and back-end" architecture, and the traditional session mode authentication is no longer suitable for this architecture (or a lot of additional code needs to be written for special adaptation).

Sa-Token is a java lightweight authority authentication framework, which is specially built for front-end and back-end separation architectures. It mainly solves a series of authority-related issues such as login authentication, authority authentication, single sign-on, OAuth2, and micro-service gateway authentication.

Gitee open source address: https://gitee.com/dromara/sa-token

This article will introduce the front-end and back-end separation projects under the Springboot architecture, and how to use Sa-Token to conveniently complete login authentication.

First introduce the Sa-Token dependency in the project:

<!-- Sa-Token 权限认证 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.34.0</version>
</dependency>

Note: If you are using SpringBoot 3.x, just sa-token-spring-boot-starterchange to sa-token-spring-boot3-starter.

2. No cookie mode

No cookie mode: It refers specifically to terminals that do not support the cookie function. Generally speaking, it is what we often say - the front-end and back-end separation mode .

Conventional web-side authentication methods are generally Cookie模式completed by , and cookies have two characteristics:

  1. Writable by backend control.
  2. Submitted automatically on every request.

This allows us to complete the entire process of authentication without any special operations in the front-end code (because the entire process is completed by the back-end control)

. For the function of cookies, most people will be confused at this time, how to perform authentication?

See tricks, the answer is actually very simple:

  • If the backend cannot control the writing, the frontend writes by itself. (The difficulty lies in how the backend passes the Token to the frontend )
  • If each request cannot be submitted automatically, submit it manually. (The difficulty lies in how the front end passes the Token to the back end , and the back end reads it out at the same time )

3. The backend returns the token to the frontend

  1. First call StpUtil.login(id)to log in.
  2. Call StpUtil.getTokenInfo()Returns the token detailed parameters of the current session.
    • This method returns an object with two key properties: tokenNameand tokenValue(the name of the token and the value of the token).
    • Pass this object to the foreground and let the front-end staff save these two values ​​locally.

Code example:

// 登录接口
@RequestMapping("doLogin")
public SaResult doLogin() {
   
	// 第1步,先登录上 
	StpUtil.login(10001);
	// 第2步,获取 Token 相关参数 
	SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
	// 第3步,返回给前端 
	return SaResult.data(tokenInfo);
}

4. The front end submits the token to the back end

  1. Whether it is an app or a small program, the delivery methods are similar.
  2. That is, insert the token into the request headerin the format: {tokenName: tokenValue}.
  3. Take the classic cross-end framework uni-app as an example:

Method 1, simple and rude

// 1、首先在登录时,将 tokenValue 存储在本地,例如:
uni.setStorageSync('tokenValue', tokenValue);

// 2、在发起ajax请求的地方,获取这个值,并塞到header里 
uni.request({
   
	url: 'https://www.example.com/request', // 仅为示例,并非真实接口地址。
	header: {
   
		"content-type": "application/x-www-form-urlencoded",
		"satoken": uni.getStorageSync('tokenValue')		// 关键代码, 注意参数名字是 satoken 
	},
	success: (res) => {
   
		console.log(res.data);	
	}
});

Method 2, more flexible

// 1、首先在登录时,将tokenName和tokenValue一起存储在本地,例如:
uni.setStorageSync('tokenName', tokenName); 
uni.setStorageSync('tokenValue', tokenValue); 

// 2、在发起ajax的地方,获取这两个值, 并组织到head里 
var tokenName = uni.getStorageSync('tokenName');	// 从本地缓存读取tokenName值
var tokenValue = uni.getStorageSync('tokenValue');	// 从本地缓存读取tokenValue值
var header = {
   
	"content-type": "application/x-www-form-urlencoded"
};
if (tokenName != undefined && tokenName != '') {
   
	header[tokenName] = tokenValue;
}

// 3、后续在发起请求时将 header 对象塞到请求头部 
uni.request({
   
	url: 'https://www.example.com/request', // 仅为示例,并非真实接口地址。
	header: header,
	success: (res) => {
   
		console.log(res.data);	
	}
});
  1. As long as tokenthe value is passed to the backend in this way, Sa-Token can automatically read the token value for authentication just like the traditional PC side.
  2. You may have doubts, do I have to ajaxwrite such a pile every time? Isn't it troublesome?
    • Of course, you can't write such a pile of every ajax, because this kind of repetitive code must be encapsulated in a function and called uniformly.

Other solutions:

If you know very well about cookies, then you will understand that the so-called cookie is essentially a special headerparameter,
and since it is only a header parameter, we can manually simulate and implement it to complete the authentication operation.

This is actually 无Cookie模式another correct solution. Interested students can find out about it on Baidu, so I won’t go into details here.

5. Code comparison

In order to more intuitively show the difference between the front-end and back-end integrated architecture and the front-end and back-end separation architecture, here is another example:

package com.pj.cases.up;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;

/** * Sa-Token 前后端分离模式示例 * * @author kong * @since 2022-10-17 */
@RestController
@RequestMapping("/NotCookie/")
public class NotCookieController {
   

	// 前后端一体模式的登录样例 ---- http://localhost:8081/NotCookie/doLogin?name=zhang&pwd=123456
	@RequestMapping("doLogin")
	public SaResult doLogin(String name, String pwd) {
   
		if("zhang".equals(name) && "123456".equals(pwd)) {
   
			// 会话登录 
			StpUtil.login(10001);
		    return SaResult.ok();
		}
		return SaResult.error("登录失败");
	}
	
	// 前后端分离模式的登录样例 ---- http://localhost:8081/NotCookie/doLogin2?name=zhang&pwd=123456
	@RequestMapping("doLogin2")
	public SaResult doLogin2(String name, String pwd) {
   
		
		if("zhang".equals(name) && "123456".equals(pwd)) {
   
			
			// 会话登录 
			StpUtil.login(10001);
			
			// 与常规登录不同点之处:这里需要把 Token 信息从响应体中返回到前端 
			SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
		    return SaResult.data(tokenInfo);
		}
		return SaResult.error("登录失败");
	}
	
}
  • Interface 1: Token will be returned to the front end in the cookie context, and will be automatically submitted by the browser each time it requests, this mode is suitable for the front-end and back-end integrated architecture.
  • Interface 2: Token will be returned to the front-end in the response body, and will be manually stored by the front-end, and submitted manually at each request. This mode is suitable for the architecture where the front-end and back-end are separated.

6. Customize the prefix submitted by Token

In some systems, when the front-end submits the token, a fixed prefix will be added in front, for example:

{
   
	"satoken": "Bearer xxxx-xxxx-xxxx-xxxx"
}

At this time, if the backend does not do any special processing, the framework will regard it Bearer as part of the token, and cannot read the token information normally, resulting in authentication failure.

To do this, we need to add the following configuration to yml:

sa-token: 
	# token前缀
	token-prefix: Bearer

At this time, the Sa-Token can be cropped when reading the Token Bearerand obtained successfully xxxx-xxxx-xxxx-xxxx.

important point:

  1. There must be a space between the Token prefix and the Token value.
  2. Once the Token prefix is ​​configured, Tokenit must be submitted with the prefix, otherwise the framework will not be able to read the Token.
  3. Since Cookiespace characters cannot be stored in , it means that after the Token prefix is ​​configured, the Cookie authentication method will be invalid. At this time, the Token can only be submitted to for headertransmission.

7. Custom Token style

The default token generation strategy of Sa-Token is uuid style, which looks like: 623368f0-ae5e-4475-a53f-93e4225f16ae.

If you are not too interested in this style, you can also set the token generation to other styles.

How to set it? You only need to set it in the yml configuration file sa-token.token-style=风格类型, which has multiple values:

// 1. token-style=uuid —— uuid风格 (默认风格)
"623368f0-ae5e-4475-a53f-93e4225f16ae"

// 2. token-style=simple-uuid —— 同上,uuid风格, 只不过去掉了中划线
"6fd4221395024b5f87edd34bc3258ee8"

// 3. token-style=random-32 —— 随机32位字符串
"qEjyPsEA1Bkc9dr8YP6okFr5umCZNR6W"

// 4. token-style=random-六十四 —— 随机六十四位字符串
"v4ueNLEpPwMtmOPMBtOOeIQsvP8z9gkMgIVibTUVjkrNrlfra5CGwQkViDjO8jcc"

// 5. token-style=random-128 —— 随机128位字符串
"nojYPmcEtrFEaN0Otpssa8I8jpk8FO53UcMZkCP9qyoHaDbKS6dxoRPky9c6QlftQ0pdzxRGXsKZmUSrPeZBOD6kJFfmfgiRyUmYWcj4WU4SSP2ilakWN1HYnIuX0Olj"

// 6. token-style=tik —— tik风格
"gr_SwoIN0MC1ewxHX_vfCW3BothWDZMMtx__"

8. Custom Token Generation Strategy

If you feel that none of the above styles are your favorite, then you can also customize the token generation strategy to customize the token generation style.

How to do it? You only need to rewrite the algorithm SaStrategyof the strategy class createToken:

The reference steps are as follows:

1. SaTokenConfigureAdd code in the configuration class:

@Configuration
public class SaTokenConfigure {
   
    /** * 重写 Sa-Token 框架内部算法策略 */
    @Autowired
    public void rewriteSaStrategy() {
   
    	// 重写 Token 生成策略 
    	SaStrategy.me.createToken = (loginId, loginType) -> {
   
    		return SaFoxUtil.getRandomString(60);	// 随机60位长度字符串
    	};
    }
}

2. Call StpUtil.login(10001)the method again to log in, and observe the generated token style:

gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH

References

RustDesk 1.2: Using Flutter to rewrite the desktop version, supporting Wayland's alleged GPT-4 model architecture leak: Contains 1.8 trillion parameters, using a mixed expert model (MoE) Musk announced the establishment of xAI company deepin V23 successfully adapted WSL CentOS project claims " Open to all" Rust 1.71.0 Stable Release React Is it having an Angular.js moment? Microsoft launches a new default font, Aptos, to replace CalibriMicrosoft : Increase efforts to use Rust IntelliJ IDEA 2023.1.4 release on Windows 11
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/3503445/blog/9869412