授权访问
后来补充:
我另一篇博客详细讲解了一下JWT认证和普通认证的区别,可以移步到那里看看 点我引一下流嘻
吐槽: 回头看下面之前写的题解像幼稚园笔记(汗
传统模式
我们每访问一个网址,都会判断当前账号有没有权限访问当前页面,即url
分为两种类型,一种是公开的,任何人都能访问的;一种是只有授权了的账号才有权限访问当前页面。
用户在登录login
的时候,服务器会将用户登录的账号密码数据与数据库里的账号密码数据进行比对,返回一个sessionID
,并将sessionID
保存(可以理解为是保存sessionID
与username
之间的一个映射)。这样当用户访问授权页面时,用户会捎带这个sessionID
,服务器可以根据用户的sessionID
判断这个用户是否有权访问当前的页面(判断方法也很简单,直接比对一下用户捎带的sessionID
与服务器里保存的sessionID
是否一致即可)。若有效(有权),则将user
信息提取到上下文,即后面可以在Controller
中根据某种接口获取user
信息。
认证成功后,就可以访问Controller
授权链接了。
解决跨域等问题的jwt验证方式
优点:1.很容易实现跨域。2.不需要在服务器端存储,即只需要获取一个令牌,就可以用这个令牌登录多个服务器了。
原理:一个用户登录成功后,服务器会给用户一个jwt-token
,不需要存任何信息。
服务器端: userid
+ 密钥 -> 加密成新的字符串,且加密过程不可逆。
jwt-token
: userid
+ 加密后的新字符串
同时,加密过程不可逆保证了用户不能通过篡改userid
而获得非法权限。
access-token
:有效期较短,用GET
请求
refresh-toekn
:有效期较长,用POST
请求,相对较安全
添加配置
实现utils.JwtUtil
类,为jwt
工具类,用来创建、解析jwt token
实现config.filter.JwtAuthenticationTokenFilter
类,用来验证jwt
token
,如果验证成功,则将User
信息注入上下文中
配置config.SecurityConfig
类,放行登录、注册等接口
更新(2024.1.4):
鉴于 jjwt-api
, jjwt-impl
,jjwt-jackson
版本升级了,y总原来的配置文件好多方法都已经弃用,不适合新版的依赖,因此做出以下更改:
utils.JwtUtil.java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
@Component
public class JwtUtil {
public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14; // token的有效期设置为14天
public static final String JWT_KEY = "Asuka0810IVK157AXCZSChcwW23AUvayrXYhgcXAHKBMDziw17dW"; // 密钥,自己随便打,但是长度要够长,否则会报错
public static String getUUID() { // 生成一个随机的UUID并去掉其中的"-"
return UUID.randomUUID().toString().replaceAll("-", "");
}
public static SecretKey generalKey() {
byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY); // 使用Base64解码预设的JWT_KEY
return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256"); // 使用这个解码后的密钥生成一个HmacSHA256算法的SecretKey
}
private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
SecretKey secretKey = generalKey();
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
if (ttlMillis == null) {
ttlMillis = JwtUtil.JWT_TTL;
}
long expMillis = nowMillis + ttlMillis; // 计算出token的过期时间
Date expDate = new Date(expMillis);
return Jwts.builder()
.id(uuid)
.subject(subject)
.issuer("sg")
.issuedAt(now)
.signWith(secretKey)
.expiration(expDate);
}
public static String createJWT(String subject) { // 创建一个JWT。
JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
return builder.compact(); // 将其转换为一个紧凑的URL安全的JWT字符串
}
public static Claims parseJWT(String jwt) throws Exception { // 解析一个JWT
SecretKey secretKey = generalKey();
return Jwts.parser()
.verifyWith(secretKey) // 使用生成的密钥来验证JWT的签名
.build()
.parseSignedClaims(jwt)
.getPayload(); // 解析JWT并返回其payload(载荷)部分
}
}
实现api
1.Controller
,用来调用Server
里的接口
2.在Server
里写接口
3.在Server
里的impl
文件夹里,写Server
里的接口的具体实现
tips:
1.只有加了@Service
注解才能用@Autowired
注解调用。
2.所有的api
返回的都是Map<String,String>
3.@GetMapping("/user/account/info/")
,@PostMapping("/user/account/token/")
等下面的函数名其实是可以自定义的。
4.LoginServiceImpl
里的getToken
返回的map
对应前端通过$ajax.
返回的值。
这里理清一下我理解的思路(不知道准不准确哈),以loginController
为例:
//Post请求,会更安全
@PostMapping("/user/account/token/")
//将Post请求的参数放到一个map里面
public Map<String,String> work(@RequestParam Map<String,String> map) {
String username = map.get("username");
String password = map.get("password");
return loginService.getToken(username,password);
}
这里的@RequestParam
是提取当前路由链接,也就是PostMapping()
链接里的值,这里的值是由前端返回的,我们来看一下调试的前端代码:
setup() {
$.ajax({
url: "http://127.0.0.1:3000/user/account/token/",
type: "post",
data: {
username: 'yume',
password: 'xxxx',
},
success(resp) {
console.log(resp);
},
error(resp) {
console.log(resp);
}
});
}
这里的
data: {
username: 'yume',
password: 'xxxx',
},
其实就是前端返回的一个map
映射,这样每次Post
一次请求,后端都会接收到一个map<>
,这样我们就可以通过map.get("username")
和map.get("password")
得到用户的账号和密码,也就是说这是前后端一一对应的关系。
然后就是调用函数loginService.getToken(username,password)
了。
同时,在LoginServiceImpl.java
中,我们也会得到一个map
Map<String,String> map = new HashMap<>();
map.put("message", "success");
map.put("token",jwt);
return map;
这里返回的便是前端console
中我们看到的结果映射。
这样捋一捋应该就清楚了。。。如果有说错的地方望大佬及时指出,我是真不会啊QAQ
@GetMapping
就更简单了,后端直接返回一个map,前端$.ajax
直接get
就好了,注意要授权认证:
url: "http://127.0.0.1:3000/user/account/info/",
type: "get",
headers: {
Authorization: "Bearer " + 你的token //授权
},
剩下的注册也是一样的,值得注意的是,我新增用户的时候没有在数据库里将id列设定为自动增长,导致注册Post
的时候,出现了500
错误。这里写一下教训,前端出现错误的时候,有可能是你前端写错了什么,但更大的可能是你后端出错了,我在这里卡了好久都没发现,实在是太蠢了o(╯□╰)o
SQLserver里默认不能将已建好的数据表更改属性,需要在本地SSMS里设置一下:
方法:点击需要设置的表,点击右键——设计——在列中,点击id——>点击标识规范,可以看到默认为否,代表不递增–>将标识规范调为是,增量设置为1,点击保存按钮,需要注意的是这种方法只在创建表的时候有用,如果已经创建表成功了,再来修改会出现错误。
防止报错的方法前面也提到了,需要在工具 –> 选项 –> Designers下去掉“组织保存要求重新创建表的更改”
这样就可以愉快地将新注册的用户加入到数据库里了,id会自动递增滴~~
编写前端
后端搞完后,我们就开始写前端了
前端看多了写的都差不多,这里就不赘述了
记几个比较容易遗忘的点:
1. import { useStore } from 'vuex'; //全局变量
是调用全局变量
2. /store/index.js
或者是自己新建立的/store/user.js
中的
state
: 存储所有数据,可以用modules
属性划分成若干模块
getters
:根据state
中的值计算新的值
mutations
:所有对state
的修改操作都需要定义在这里,不支持异步,可以通过$store.commit()
触发
actions
:定义对state
的复杂修改操作,支持异步,可以通过$store.dispatch()
触发。注意不能直接修改state
,只能通过mutations
修改state
。
modules
:定义state
的子模块
3. 前后端交互的形式长得都和下面差不多:
login(context, data) {
$.ajax({
url: "http://127.0.0.1:3000/user/account/token/",
type: "post",
data: {
username: data.username,
password: data.password,
},
success(resp) {
//调用mutations里的函数,需要用commit + 函数名
//这里的resp是返回的后端传来的值,都是自己定义的,注意要与后端相匹配
if (resp.message === "success") {
context.commit("updateToken", resp.token);
data.success(resp);
} else {
data.error(resp);
}
},
error(resp) {
data.error(resp);
}
});
},
4.登录与注册模块都差不多,退出的话则把data
里面的数据全部清空掉就好了,相当于把jwt
令牌直接扔掉。
更新,补充了详细的前后端步骤
配置Mysql
与注册登录模块
Mysql
常用操作
mysql
服务的关闭与启动(默认开机自动启动,如果想要手动操作,可以参考如下命令)、- 关闭:
net stop mysql80
- 启动:
net start mysql80
- 连接用户名为
root
,密码为123456
的数据库服务:mysql -uroot -p密码
show databases;
列出所有数据库create databases kob;
创建数据库drop databases kob;
删除数据库use kob;
使用数据库show tables;
列出当前数据库的所有表create table user(id int,username varchar(100));
创建名称为user
的表,表中包含id
和username
drop table user
删除表insert into user values(1,'myname')
在表中插入数据select * from user;
查询表中所有数据delete from user where id = 2
删除某行数据update table_name set column1 = value1 ... where [condition]
: 修改满足条件的某一行的数据
配置SpringBoot
在pom.xml
文件中添加依赖
Spring Boot Starter JDBC
Project Lombok
MySQL Connector/J
mybatis-plus-boot-starter
mybatis-plus-generator
spring-boot-starter-security
在application.properties
中添加数据库配置:
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/kob?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
配置JWT
认证
添加依赖:
jjwt-api
jjwt-impl
jjwt-jackson
新版的jwt
认证配置文件:
新建utils
文件夹,在里面创建JwtUtil.java
package com.gameforces.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
@Component
public class JwtUtil {
public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14; // token的有效期设置为14天
public static final String JWT_KEY = "Asuka0810IVK157AXCZSChcwW23AUvayrXYhgcXAHKBMDziw17dW"; // 密钥,自己随便打,但是长度要够长,否则会报错
public static String getUUID() { // 生成一个随机的UUID并去掉其中的"-"
return UUID.randomUUID().toString().replaceAll("-", "");
}
public static SecretKey generalKey() {
byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY); // 使用Base64解码预设的JWT_KEY
return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256"); // 使用这个解码后的密钥生成一个HmacSHA256算法的SecretKey
}
private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
SecretKey secretKey = generalKey();
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
if (ttlMillis == null) {
ttlMillis = JwtUtil.JWT_TTL;
}
long expMillis = nowMillis + ttlMillis; // 计算出token的过期时间
Date expDate = new Date(expMillis);
return Jwts.builder()
.id(uuid)
.subject(subject)
.issuer("sg")
.issuedAt(now)
.signWith(secretKey)
.expiration(expDate);
}
public static String createJWT(String subject) { // 创建一个JWT。
JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
return builder.compact(); // 将其转换为一个紧凑的URL安全的JWT字符串
}
public static Claims parseJWT(String jwt) throws Exception { // 解析一个JWT
SecretKey secretKey = generalKey();
return Jwts.parser()
.verifyWith(secretKey) // 使用生成的密钥来验证JWT的签名
.build()
.parseSignedClaims(jwt)
.getPayload(); // 解析JWT并返回其payload(载荷)部分
}
}
config.filter.JwtAuthenticationTokenFilter.java
这个配置与我们从前端获取后端数据的协议有关
package com.gameforces.backend.config.filter;
import com.gameforces.backend.mapper.UserMapper;
import com.gameforces.backend.pojo.User;
import com.gameforces.backend.service.impl.utils.UserDetailsImpl;
import com.gameforces.backend.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserMapper userMapper;
@Override
protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("Authorization"); // 从请求头中获取名为"Authorization"的字段
if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) { // 这个字段应该包含一个以"Bearer "开头的JWT
filterChain.doFilter(request, response); // 将请求传递给下一个过滤器或处理器
return;
}
token = token.substring(7); // 跳过"Bearer "共7个字符
String userid;
try {
Claims claims = JwtUtil.parseJWT(token); // 解析JWT,获取JWT的载荷
userid = claims.getSubject(); // 从载荷中获取"subject",这个"subject"应该是用户ID
} catch (Exception e) {
throw new RuntimeException(e);
}
User user = userMapper.selectById(Integer.parseInt(userid)); // 查询数据库获取用户信息
if (user == null) {
throw new RuntimeException("用户未登录");
}
UserDetailsImpl loginUser = new UserDetailsImpl(user);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser, null, null);
SecurityContextHolder.getContext().setAuthentication(authenticationToken); // 将其设置到Spring Security的上下文中
filterChain.doFilter(request, response); // 将请求传递给下一个过滤器或处理器
}
}
配置Spring Security
结合Jwt
认证
config.SecurityConfig.java
package com.gameforces.backend.config;
import com.gameforces.backend.config.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManagerBean(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/user/account/token/", "/user/account/register/").permitAll()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated();
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/websocket/**");
}
}
完善数据库user
表的pojo
层
public class User { //这里名字与数据库里的名字需要一致
@TableId(type = IdType.AUTO) //实现id自增
private Integer id;
private String username;
private String password;
private String photo;
}
编写与实现登陆注册接口
登录接口(service
层):
package com.gameforces.backend.service.user.account;
import java.util.Map;
public interface LoginService {
Map<String, String> getToken(String username, String password);
}
实现登陆接口:
package com.gameforces.backend.service.impl.user.account;
import com.gameforces.backend.pojo.User;
import com.gameforces.backend.service.impl.utils.UserDetailsImpl;
import com.gameforces.backend.service.user.account.LoginService;
import com.gameforces.backend.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service // 注入到Spring中,未来可以用@Autowired注解将该类注入到某个其他类中
public class LoginServiceImpl implements LoginService {
@Autowired
private AuthenticationManager authenticationManager; //验证用户是否登录成功
@Override
public Map<String, String> getToken(String username, String password) {
//封装用户名密码(因为用户名密码存储用的不是明文)
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(username, password);
//authenticationManager.authenticate(authenticationToken).var();
Authentication authenticate = authenticationManager.authenticate(authenticationToken); //如果登陆失败,会自动处理报异常
//将用户取出来
UserDetailsImpl loginUser = (UserDetailsImpl) authenticate.getPrincipal();
User user = loginUser.getUser();
//将UserID包装成一个jwt-token
String jwt = JwtUtil.createJWT(user.getId().toString());
Map<String, String> map = new HashMap<>();
map.put("message", "success");
map.put("token", jwt);
return map;
}
}
编写Controller
层
定义API
为/api/user/account/token
controller.user.account.LoginController.java
package com.gameforces.backend.controller.user.account;
import com.gameforces.backend.service.user.account.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class LoginController {
@Autowired
private LoginService loginService;
//Post请求,会更安全
@PostMapping("/api/user/account/token/")
//将Post请求的参数(data)放到一个map里面: @RequestParam
public Map<String, String> getToken(@RequestParam Map<String, String> map) {
String username = map.get("username");
String password = map.get("password");
return loginService.getToken(username, password);
}
}
编写获取用户信息的getInfo
接口,与用户注册接口register
道理都是差不多的,这里就不仔细展示了
给出注册的基本逻辑
service.impl.user.account.RegisterServiceImpl.java
package com.gameforces.backend.service.impl.user.account;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gameforces.backend.mapper.UserMapper;
import com.gameforces.backend.pojo.User;
import com.gameforces.backend.service.user.account.RegisterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class RegisterServiceImpl implements RegisterService {
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public Map<String, String> register(String username, String password, String confirmedPassword) {
Map<String, String> map = new HashMap<>();
if (username == null) {
map.put("message", "用户名不能为空");
return map;
}
if (password == null || confirmedPassword == null) {
map.put("message", "密码不能为空");
return map;
}
username = username.trim();//将首尾空格都去掉
if (username.length() == 0) {
map.put("message", "用户名不能为空");
return map;
}
if (password.length() == 0 || confirmedPassword.length() == 0) {
map.put("message", "密码不能为空");
return map;
}
if (username.length() > 100) {
map.put("message", "用户名长度不能大于100");
return map;
}
if (password.length() > 100 || confirmedPassword.length() > 100) {
map.put("message", "密码长度不能大于100");
return map;
}
if (!password.equals(confirmedPassword)) {
map.put("message", "两次输入的密码不一致");
return map;
}
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username); // 在数据库中查看是否存在用户名相同的用户
List<User> users = userMapper.selectList(queryWrapper);
if (!users.isEmpty()) {
map.put("message", "用户名已存在");
return map;
}
//执行数据库插入操作
String encodedPassword = passwordEncoder.encode(password); //将密码加密
String photo = "https://cdn.acwing.com/media/user/profile/photo/118375_lg_e2515ed3ad.jpg";
User user = new User(null, username, encodedPassword, photo);
userMapper.insert(user);
map.put("message", "success");
return map;
}
}
编写登陆注册前端
这部分之前写过了,这里就不写了
感兴趣可以看这里的笔记
用vuex
维护用户信息
在store.index.js
中引入自己编写的user
模块
import { createStore } from 'vuex'
import ModuleUser from './user'
// import ModulePk from './pk'
// import ModuleRecord from './record'
export default createStore({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
user: ModuleUser,
// pk: ModulePk,
// record: ModuleRecord,
}
})
store.user.js
import $ from "jquery";
export default {
state: {
id: "",
username: "",
photo: "",
token: "",
rating: "",
is_login: false,
view_name: "",
loading: true, //是否正在加载信息
},
getters: {
},
mutations: { // 用来修改数据
updateUser(state, user) {
state.id = user.id;
state.username = user.username;
state.photo = user.photo;
state.rating = user.rating;
state.is_login = user.is_login;
},
updateToken(state, token) {
state.token = token;
},
updateName(state, view_name) {
state.view_name = view_name;
},
updateLoading(state, loading) {
state.loading = loading;
},
updateLogout(state, user) {
state.id = user.id;
state.username = user.username;
state.photo = user.photo;
state.is_login = user.is_login;
state.token = user.token;
},
},
actions: {
login: (context, data) => {
$.ajax({
url: "http://127.0.0.1:3000/api/user/account/token/",
type: "post",
data: {
username: data.username,
password: data.password,
},
success: resp => {
//调用mutations里的函数,需要用commit + 函数名
//这里的resp是返回的后端传来的值,都是自己定义的,注意要与后端相匹配
if (resp.message === "success") {
localStorage.setItem("jwt_token", resp.token); // 将令牌存到LocalStorage中实现登录状态持久化
//let name = localStorage.getItem("routerName");
//context.commit("updateName",name);
context.commit("updateToken", resp.token);
data.success();
} else {
data.error();
}
},
error(resp) {
data.error(resp);
}
});
},
getinfo(context, data) {
$.ajax({
url: "http://127.0.0.1:3000/api/user/account/info/",
type: "get",
headers: {
// 不是固定的,是官方推荐的写法,Authorization是在我们的后端JwtAuthenticationTokenFilter类中设置的
Authorization: "Bearer " + context.state.token,//授权
},
success: resp => {
if (resp.message === "success") {
//console.log(resp);
context.commit("updateUser", { ...resp, is_login: true });
data.success();
}
else data.error();
},
error: () => {
data.error();
}
});
},
logout(context) {
localStorage.removeItem("jwt_token");
context.commit("updateLogout", {
id: "",
username: "",
photo: "",
rating: "",
is_login: false,
token: "",
//loading: true,
//view_name: "",
})
}
},
modules: {
}
}
Ending
这次大概就只写好了后端的注册,信息,登录处理,与前端的注册页面与登录页面,我自己写的大概长这样,
还有好多不会,继续努力啦QAQ
data.error is not a function
好帅的注册登录页面
能分享一下嘛