Login + getInfo + Register 后端 API 书写, login + logout 前端书写
This commit is contained in:
		
							parent
							
								
									78db9a28c8
								
							
						
					
					
						commit
						0badc0f83d
					
				@ -68,6 +68,30 @@
 | 
			
		||||
            <version>3.0.2</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
<!--        用于使用 JWT 验证-->
 | 
			
		||||
        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>io.jsonwebtoken</groupId>
 | 
			
		||||
            <artifactId>jjwt-api</artifactId>
 | 
			
		||||
            <version>0.11.5</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>io.jsonwebtoken</groupId>
 | 
			
		||||
            <artifactId>jjwt-impl</artifactId>
 | 
			
		||||
            <version>0.11.5</version>
 | 
			
		||||
            <scope>runtime</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>io.jsonwebtoken</groupId>
 | 
			
		||||
            <artifactId>jjwt-jackson</artifactId>
 | 
			
		||||
            <version>0.11.5</version>
 | 
			
		||||
            <scope>runtime</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework.boot</groupId>
 | 
			
		||||
@ -83,6 +107,12 @@
 | 
			
		||||
            <artifactId>spring-boot-starter-test</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.jetbrains</groupId>
 | 
			
		||||
            <artifactId>annotations</artifactId>
 | 
			
		||||
            <version>13.0</version>
 | 
			
		||||
            <scope>compile</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 | 
			
		||||
@ -1,17 +1,55 @@
 | 
			
		||||
package com.kob.backend.config;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
主要作用:放行登录、注册等接口
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import com.kob.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.web.builders.HttpSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 | 
			
		||||
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.authentication.UsernamePasswordAuthenticationFilter;
 | 
			
		||||
 | 
			
		||||
// TODO: 2023/2/19  WebSecurityConfigurerAdapter 已被弃用,注意替换
 | 
			
		||||
@Configuration
 | 
			
		||||
@EnableWebSecurity
 | 
			
		||||
public class SecurityConfig {
 | 
			
		||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
 | 
			
		||||
 | 
			
		||||
//    配置密码加密方式
 | 
			
		||||
    @Bean
 | 
			
		||||
    public PasswordEncoder passwordEncoder() {
 | 
			
		||||
        return new BCryptPasswordEncoder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    @Override
 | 
			
		||||
    public AuthenticationManager authenticationManagerBean() throws Exception {
 | 
			
		||||
        return super.authenticationManagerBean();
 | 
			
		||||
    }
 | 
			
		||||
/*
 | 
			
		||||
    .antMatchers("/user/account/token/", "/user/account/register/").permitAll()
 | 
			
		||||
    用于配置公开链接
 | 
			
		||||
*/
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void configure(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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,68 @@
 | 
			
		||||
package com.kob.backend.config.filter;
 | 
			
		||||
 | 
			
		||||
//filter 类用于验证
 | 
			
		||||
/*
 | 
			
		||||
主要作用:
 | 
			
		||||
        1. 用来验证jwt token,如果验证成功,则将User信息注入上下文中
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import com.kob.backend.mapper.UserMapper;
 | 
			
		||||
import com.kob.backend.pojo.User;
 | 
			
		||||
import com.kob.backend.service.impl.utils.UserDetailsImpl;
 | 
			
		||||
import com.kob.backend.utils.JwtUtil;
 | 
			
		||||
import com.sun.xml.internal.bind.v2.TODO;
 | 
			
		||||
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");
 | 
			
		||||
 | 
			
		||||
//        TODO 这里可以更改 bearar 为其他字符作为验证前缀
 | 
			
		||||
        if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
 | 
			
		||||
            filterChain.doFilter(request, response);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        token = token.substring(7);
 | 
			
		||||
 | 
			
		||||
        String userid;
 | 
			
		||||
        try {
 | 
			
		||||
            Claims claims = JwtUtil.parseJWT(token);
 | 
			
		||||
            userid = claims.getSubject();
 | 
			
		||||
        } 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);
 | 
			
		||||
 | 
			
		||||
        filterChain.doFilter(request, response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -12,7 +12,8 @@ import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
//实现对用户类 User 的增删查操作
 | 
			
		||||
//实现对用户类 User 的增删查操作->这个类仅用于调试,故 Deparecated 掉
 | 
			
		||||
@Deprecated
 | 
			
		||||
@RestController
 | 
			
		||||
public class UserController {
 | 
			
		||||
 | 
			
		||||
@ -58,7 +59,7 @@ public class UserController {
 | 
			
		||||
//        加密明文密码并存入密文到数据库
 | 
			
		||||
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
 | 
			
		||||
        String encodedPassword = passwordEncoder.encode(password);
 | 
			
		||||
        User user = new User(userId, username, encodedPassword);
 | 
			
		||||
        User user = new User(userId, username, encodedPassword,"");
 | 
			
		||||
        userMapper.insert(user);
 | 
			
		||||
        return "Add User Successfully";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
package com.kob.backend.controller.user.account;
 | 
			
		||||
 | 
			
		||||
import com.kob.backend.service.user.account.InfoService;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
public class InfoController {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private InfoService infoService;
 | 
			
		||||
 | 
			
		||||
//    获取信息
 | 
			
		||||
    @GetMapping("/user/account/info/")
 | 
			
		||||
    public Map<String,String> getInfo(){
 | 
			
		||||
        return infoService.getInfo();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
package com.kob.backend.controller.user.account;
 | 
			
		||||
 | 
			
		||||
import com.kob.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 配合 @PostMapping("/.../.../") 使用:映射 Url 地址
 | 
			
		||||
@RestController
 | 
			
		||||
public class LoginController {
 | 
			
		||||
//    @Autowired 注入接口
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private LoginService loginService;
 | 
			
		||||
 | 
			
		||||
//    登录使用 POST 请求,密文传输,更安全
 | 
			
		||||
    @PostMapping("/user/account/token/")
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,24 @@
 | 
			
		||||
package com.kob.backend.controller.user.account;
 | 
			
		||||
 | 
			
		||||
import com.kob.backend.service.user.account.RegisterService;
 | 
			
		||||
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 RegisterController {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RegisterService registerService;
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/user/account/register/")
 | 
			
		||||
    public Map<String, String> register(@RequestParam Map<String, String> map) {
 | 
			
		||||
        String username = map.get("username");
 | 
			
		||||
        String password = map.get("password");
 | 
			
		||||
        String confirmedPassword = map.get("confirmedPassword");
 | 
			
		||||
        return registerService.register(username, password, confirmedPassword);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -6,6 +6,8 @@ Data 用于编译时自动生成 getter setter 方法;
 | 
			
		||||
NoArgsConstructor 用于生成无参构造函数;
 | 
			
		||||
AllArgsConstructor 用于生成所有参数构造函数.
 | 
			
		||||
*/
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.IdType;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableId;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
@ -16,8 +18,11 @@ import lombok.NoArgsConstructor;
 | 
			
		||||
public class User {
 | 
			
		||||
 | 
			
		||||
//      使用对象类型定义而不是 Int 防止 Mybatis 报错
 | 
			
		||||
//    @TableId(type = IdType.AUTO) 用于 id 的自增
 | 
			
		||||
    @TableId(type = IdType.AUTO)
 | 
			
		||||
    private Integer id;
 | 
			
		||||
    private String username;
 | 
			
		||||
    private String password;
 | 
			
		||||
    private String photo;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,12 @@ public class UserDetailsServiceImpl implements UserDetailsService {
 | 
			
		||||
    private UserMapper userMapper;
 | 
			
		||||
    @Override
 | 
			
		||||
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
 | 
			
		||||
/*
 | 
			
		||||
        从数据库里读取用户信息,比对用户名密码与数据库存在的用户名密码,信息一致,给用户发一个 sessionID ,
 | 
			
		||||
        存到用户本地浏览器,服务器同时会自己存一份。未来用户再登录时服务器会将自己的 sessionID 与用户发过来
 | 
			
		||||
        请求包含的 sessionID 进行比照,如果一致,则授权成功。
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
 | 
			
		||||
        queryWrapper.eq("username",username);
 | 
			
		||||
        User user = userMapper.selectOne(queryWrapper);
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,34 @@
 | 
			
		||||
package com.kob.backend.service.impl.user.account;
 | 
			
		||||
 | 
			
		||||
import com.kob.backend.pojo.User;
 | 
			
		||||
import com.kob.backend.service.impl.utils.UserDetailsImpl;
 | 
			
		||||
import com.kob.backend.service.user.account.InfoService;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class InfoServiceImpl implements InfoService {
 | 
			
		||||
    @Override
 | 
			
		||||
    public Map<String, String> getInfo() {
 | 
			
		||||
        UsernamePasswordAuthenticationToken authenticationToken =
 | 
			
		||||
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
 | 
			
		||||
 | 
			
		||||
        UserDetailsImpl loginUser = (UserDetailsImpl) authenticationToken.getPrincipal();
 | 
			
		||||
        User user = loginUser.getUser();
 | 
			
		||||
 | 
			
		||||
        Map<String,String> map = new HashMap<>();
 | 
			
		||||
        map.put("error_message","success");
 | 
			
		||||
        map.put("id",user.getId().toString());
 | 
			
		||||
        map.put("username",user.getUsername());
 | 
			
		||||
        map.put("photo",user.getPhoto());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,50 @@
 | 
			
		||||
package com.kob.backend.service.impl.user.account;
 | 
			
		||||
 | 
			
		||||
import com.kob.backend.pojo.User;
 | 
			
		||||
import com.kob.backend.service.impl.utils.UserDetailsImpl;
 | 
			
		||||
import com.kob.backend.service.user.account.LoginService;
 | 
			
		||||
import com.kob.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 里面
 | 
			
		||||
@Service
 | 
			
		||||
public class LoginServiceImpl implements LoginService {
 | 
			
		||||
 | 
			
		||||
//    @Autowired 用于注入
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private AuthenticationManager authenticationManager;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Map<String, String> getToken(String username, String password) {
 | 
			
		||||
 | 
			
		||||
//        封装用户名和密码成 UsernamePasswordAuthenticationToken 类:此类不存储明文,而是存储加密之后的字符串
 | 
			
		||||
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,password);
 | 
			
		||||
 | 
			
		||||
//        验证是否正常登录,登录验证失败时会自动处理(报异常)
 | 
			
		||||
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
 | 
			
		||||
//        登录成功,取出用户
 | 
			
		||||
        UserDetailsImpl loginUser = (UserDetailsImpl) authenticate.getPrincipal();
 | 
			
		||||
        User user = loginUser.getUser();
 | 
			
		||||
 | 
			
		||||
//        封装 jwt 信息:将 userID 转换为 String
 | 
			
		||||
        String jwt = JwtUtil.createJWT(user.getId().toString());
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
        成功之后返回结果:
 | 
			
		||||
        1. "error_message" 为 success;失败之后会报异常,自动处理掉
 | 
			
		||||
        2. "token" 返回 jwt-token 信息
 | 
			
		||||
*/
 | 
			
		||||
        Map<String,String> map = new HashMap<>();
 | 
			
		||||
        map.put("error_message","success");
 | 
			
		||||
        map.put("token",jwt);
 | 
			
		||||
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,81 @@
 | 
			
		||||
package com.kob.backend.service.impl.user.account;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 | 
			
		||||
import com.kob.backend.pojo.User;
 | 
			
		||||
import com.kob.backend.mapper.UserMapper;
 | 
			
		||||
import com.kob.backend.service.user.account.RegisterService;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class RegisterServiceImpl implements RegisterService {
 | 
			
		||||
    //    这里使用 @Autowired 注入是为了调用数据库,然后进行数据库查询,比较是否有用户名重复
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private UserMapper userMapper;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Map<String, String> register(String username, String password, String confirmedPassword) {
 | 
			
		||||
        Map<String, String> map = new HashMap<>();
 | 
			
		||||
//        如果用户名为空,则提示用户返回
 | 
			
		||||
        if (username == null) {
 | 
			
		||||
            map.put("error_message", "用户名不能为空");
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
        if (password == null || confirmedPassword == null) {
 | 
			
		||||
            map.put("error_message", "密码不能为空");
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
//        用户名需要将输入的首尾空格删掉
 | 
			
		||||
        username = username.trim();
 | 
			
		||||
        if (username.length() == 0) {
 | 
			
		||||
            map.put("error_message", "用户名不能为空");
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
        if (password.length() == 0) {
 | 
			
		||||
            map.put("error_message", "密码不能为空");
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
        if (username.length() > 100) {
 | 
			
		||||
            map.put("error_message", "用户名过长");
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
        if (password.length() > 100 || confirmedPassword.length() > 100) {
 | 
			
		||||
            map.put("error_message", "密码过长");
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
//        密码验证是 String 类型比较,应该用 equals() 方法
 | 
			
		||||
        if (!confirmedPassword.equals(password)) {
 | 
			
		||||
            map.put("error_message", "两次密码输入不一致");
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
        查询数据库里是否有用户名 this.username 已存在的用户,并将结果存入 users 中,
 | 
			
		||||
        如果发现 users 不是空的,则告诉注册用户当前用户名已存在
 | 
			
		||||
*/
 | 
			
		||||
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
 | 
			
		||||
        queryWrapper.eq("username", username);
 | 
			
		||||
        List<User> users = userMapper.selectList(queryWrapper);
 | 
			
		||||
        if (!users.isEmpty()) {
 | 
			
		||||
            map.put("error_message", "用户名已存在");
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
//        异常情况判断结束,开始将合法用户注册信息注入数据库
 | 
			
		||||
//        对密码进行加密
 | 
			
		||||
        String encodedPassword = new BCryptPasswordEncoder().encode(password);
 | 
			
		||||
//        默认头像
 | 
			
		||||
        String photo = "https://cdn.acwing.com/media/user/profile/photo/253652_lg_e3d8435b66.jpg";
 | 
			
		||||
//        id 是数据库自增,这里生成新用户只需要将 id 参数写为 null 即可
 | 
			
		||||
        User user = new User(null,username,encodedPassword,photo);
 | 
			
		||||
        userMapper.insert(user);
 | 
			
		||||
 | 
			
		||||
        map.put("error_message","成功注册");
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
package com.kob.backend.service.user.account;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
//根据令牌返回用户信息
 | 
			
		||||
public interface InfoService {
 | 
			
		||||
    public Map<String,String> getInfo();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
package com.kob.backend.service.user.account;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
//验证用户名密码,验证成功后返回jwt token(令牌)
 | 
			
		||||
public interface LoginService {
 | 
			
		||||
    public Map<String,String> getToken(String username, String password);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,9 @@
 | 
			
		||||
package com.kob.backend.service.user.account;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
//注册账号
 | 
			
		||||
public interface RegisterService {
 | 
			
		||||
//    confirmedPassword 密码确认
 | 
			
		||||
    public Map<String,String> register(String username, String password, String confirmedPassword);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								backend/src/main/java/com/kob/backend/utils/JwtUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								backend/src/main/java/com/kob/backend/utils/JwtUtil.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package com.kob.backend.utils;
 | 
			
		||||
 | 
			
		||||
//jwt工具类,用来创建、解析 jwt token
 | 
			
		||||
/*
 | 
			
		||||
主要作用:
 | 
			
		||||
        1. 将字符串加上密钥,加上有效期,转换为加密后的字符串;
 | 
			
		||||
        2. 给一个令牌,将其 userID 解析出来.
 | 
			
		||||
 | 
			
		||||
依赖:添加到 pom.xml 中,然后使用 Maven 重新加载依赖项
 | 
			
		||||
    jjwt-apt;
 | 
			
		||||
    jjwt-impl;
 | 
			
		||||
    jjwt-jackson.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import io.jsonwebtoken.Claims;
 | 
			
		||||
import io.jsonwebtoken.JwtBuilder;
 | 
			
		||||
import io.jsonwebtoken.Jwts;
 | 
			
		||||
import io.jsonwebtoken.SignatureAlgorithm;
 | 
			
		||||
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;  // 有效期14天:单位-毫秒 ms
 | 
			
		||||
    public static final String JWT_KEY = "SDFGjhdsfalshdfHFdsjkdsfds121232113afasdfad"; // 密钥:随机字符串-大小写英文字母+数字
 | 
			
		||||
 | 
			
		||||
    public static String getUUID() {
 | 
			
		||||
        return UUID.randomUUID().toString().replaceAll("-", "");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String createJWT(String subject) {
 | 
			
		||||
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
 | 
			
		||||
        return builder.compact();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
 | 
			
		||||
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
 | 
			
		||||
        SecretKey secretKey = generalKey();
 | 
			
		||||
        long nowMillis = System.currentTimeMillis();
 | 
			
		||||
        Date now = new Date(nowMillis);
 | 
			
		||||
        if (ttlMillis == null) {
 | 
			
		||||
            ttlMillis = JwtUtil.JWT_TTL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        long expMillis = nowMillis + ttlMillis;
 | 
			
		||||
        Date expDate = new Date(expMillis);
 | 
			
		||||
        return Jwts.builder()
 | 
			
		||||
                .setId(uuid)
 | 
			
		||||
                .setSubject(subject)
 | 
			
		||||
                .setIssuer("sg")
 | 
			
		||||
                .setIssuedAt(now)
 | 
			
		||||
                .signWith(signatureAlgorithm, secretKey)
 | 
			
		||||
                .setExpiration(expDate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static SecretKey generalKey() {
 | 
			
		||||
        byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
 | 
			
		||||
        return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Claims parseJWT(String jwt) throws Exception {
 | 
			
		||||
        SecretKey secretKey = generalKey();
 | 
			
		||||
        return Jwts.parserBuilder()
 | 
			
		||||
                .setSigningKey(secretKey)
 | 
			
		||||
                .build()
 | 
			
		||||
                .parseClaimsJws(jwt)
 | 
			
		||||
                .getBody();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -10,9 +10,56 @@ import NavBar from "./components/NavBar.vue";
 | 
			
		||||
// 导入 BootStrap 的 css 和 js 依赖以同步 BootStrap 样式
 | 
			
		||||
import "bootstrap/dist/css/bootstrap.css";
 | 
			
		||||
import "bootstrap/dist/js/bootstrap";
 | 
			
		||||
// import $ from "jquery";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  components: { NavBar },
 | 
			
		||||
  /*   setup: () => {
 | 
			
		||||
    $.ajax({
 | 
			
		||||
      url: "http://localhost:3000/user/account/token/",
 | 
			
		||||
      type: "POST",
 | 
			
		||||
      data: {
 | 
			
		||||
        username: "bb",
 | 
			
		||||
        password: "pbb",
 | 
			
		||||
      },
 | 
			
		||||
      success(resp) {
 | 
			
		||||
        console.log(resp.token, "\n成功了\n", resp.error_message);
 | 
			
		||||
      },
 | 
			
		||||
      error(resp) {
 | 
			
		||||
        console.log(resp);
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    $.ajax({
 | 
			
		||||
      url: "http://localhost:3000/user/account/info/",
 | 
			
		||||
      type: "GET",
 | 
			
		||||
      headers: {
 | 
			
		||||
        Authorization:
 | 
			
		||||
          "Bearer " +
 | 
			
		||||
          "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIzODA2Yzc0ODkwYTE0NTgwYjcyOGQzOWI4NDYyYWY2ZSIsInN1YiI6IjYiLCJpc3MiOiJzZyIsImlhdCI6MTY3Njg4ODk5MywiZXhwIjoxNjc4MDk4NTkzfQ.mq7Xdt3G7VGvX7fgIYGN2MfH8bo9MuZ7V0nfzGmbDZ8",
 | 
			
		||||
      },
 | 
			
		||||
      success(resp) {
 | 
			
		||||
        console.log(resp);
 | 
			
		||||
      },
 | 
			
		||||
      error(resp) {
 | 
			
		||||
        console.log(resp);
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    $.ajax({
 | 
			
		||||
      url: "http://localhost:3000/user/account/register/",
 | 
			
		||||
      type: "POST",
 | 
			
		||||
      data: {
 | 
			
		||||
        username: "cc",
 | 
			
		||||
        password: "pcc",
 | 
			
		||||
        confirmedPassword: "pcc",
 | 
			
		||||
      },
 | 
			
		||||
      success(resp) {
 | 
			
		||||
        console.log(resp);
 | 
			
		||||
      },
 | 
			
		||||
      error(resp) {
 | 
			
		||||
        console.log(resp);
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  }, */
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
<style>
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,8 @@
 | 
			
		||||
            >
 | 
			
		||||
          </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
        <ul class="navbar-nav">
 | 
			
		||||
        <!-- 判断是否登录成功:如果登录成功,则修改导航栏这部分内容 -->
 | 
			
		||||
        <ul class="navbar-nav" v-if="$store.state.user.is_login">
 | 
			
		||||
          <!-- 下拉菜单样式 -->
 | 
			
		||||
          <li class="nav-item dropdown">
 | 
			
		||||
            <a
 | 
			
		||||
@ -37,7 +38,7 @@
 | 
			
		||||
              data-bs-toggle="dropdown"
 | 
			
		||||
              aria-expanded="false"
 | 
			
		||||
            >
 | 
			
		||||
              flykhan
 | 
			
		||||
              {{ $store.state.user.username }}
 | 
			
		||||
            </a>
 | 
			
		||||
            <ul class="dropdown-menu">
 | 
			
		||||
              <li>
 | 
			
		||||
@ -47,10 +48,36 @@
 | 
			
		||||
              </li>
 | 
			
		||||
              <!-- 下拉菜单分割线 -->
 | 
			
		||||
              <li><hr class="dropdown-divider" /></li>
 | 
			
		||||
              <li><a class="dropdown-item" href="#">退出</a></li>
 | 
			
		||||
              <!-- v-on:click 也可以写为 @click ; 给退出按钮加上手形状按钮样式 style="cursor: pointer"-->
 | 
			
		||||
              <li>
 | 
			
		||||
                <a class="dropdown-item" style="cursor: pointer" @click="logout">退出</a>
 | 
			
		||||
              </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
          </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
 | 
			
		||||
        <ul class="navbar-nav" v-else>
 | 
			
		||||
          <!-- 下拉菜单样式 -->
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <router-link
 | 
			
		||||
              class="nav-link"
 | 
			
		||||
              :to="{ name: 'user_account_login' }"
 | 
			
		||||
              role="button"
 | 
			
		||||
            >
 | 
			
		||||
              登录
 | 
			
		||||
            </router-link>
 | 
			
		||||
          </li>
 | 
			
		||||
 | 
			
		||||
          <li class="nav-item">
 | 
			
		||||
            <router-link
 | 
			
		||||
              class="nav-link"
 | 
			
		||||
              :to="{ name: 'user_account_register' }"
 | 
			
		||||
              role="button"
 | 
			
		||||
            >
 | 
			
		||||
              注册
 | 
			
		||||
            </router-link>
 | 
			
		||||
          </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </nav>
 | 
			
		||||
@ -59,15 +86,24 @@
 | 
			
		||||
<script>
 | 
			
		||||
import { useRoute } from "vue-router";
 | 
			
		||||
import { computed } from "vue";
 | 
			
		||||
import { useStore } from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  setup() {
 | 
			
		||||
    const store = useStore();
 | 
			
		||||
    const route = useRoute();
 | 
			
		||||
    // 用于判断当前选中的是哪个 nav-link 链接,结合上文操作将选中的 nav-link 改为 nav-link active 模式
 | 
			
		||||
    let route_name = computed(() => route.name);
 | 
			
		||||
 | 
			
		||||
    const logout = () => {
 | 
			
		||||
      console.log("退出前:" + store.state.user.token);
 | 
			
		||||
      store.dispatch("logout");
 | 
			
		||||
      console.log("退出后:" + store.state.user.token);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      route_name,
 | 
			
		||||
      logout,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,8 @@ import RanklistIndexView from '../views/ranklist/RanklistIndexView.vue'
 | 
			
		||||
import RecordIndexView from '../views/record/RecordIndexView.vue'
 | 
			
		||||
import UserBotIndexView from '../views/user/bot/UserBotIndexView.vue'
 | 
			
		||||
import NotFound from '../views/error/NotFound.vue'
 | 
			
		||||
import UserAccountLoginView from '@/views/user/account/UserAccountLoginView.vue'
 | 
			
		||||
import UserAccountRegisterView from '@/views/user/account/UserAccountRegisterView.vue'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 定义所有页面的 URL 路由
 | 
			
		||||
@ -35,6 +37,16 @@ const routes = [
 | 
			
		||||
    name:'user_bot_index',
 | 
			
		||||
    component:UserBotIndexView
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path:'/user/account/login/',
 | 
			
		||||
    name:'user_account_login',
 | 
			
		||||
    component:UserAccountLoginView
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path:'/user/account/register/',
 | 
			
		||||
    name:'user_account_register',
 | 
			
		||||
    component:UserAccountRegisterView
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path:'/404/',
 | 
			
		||||
    name:'404',
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import { createStore } from 'vuex'
 | 
			
		||||
import ModuleUser from './user'
 | 
			
		||||
 | 
			
		||||
export default createStore({
 | 
			
		||||
  state: {
 | 
			
		||||
@ -10,5 +11,7 @@ export default createStore({
 | 
			
		||||
  actions: {
 | 
			
		||||
  },
 | 
			
		||||
  modules: {
 | 
			
		||||
    user: ModuleUser,
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										100
									
								
								web/src/store/user.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								web/src/store/user.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
			
		||||
import $ from 'jquery'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    state: {
 | 
			
		||||
        id: "",
 | 
			
		||||
        username: "",
 | 
			
		||||
        photo: "",
 | 
			
		||||
        token: "",
 | 
			
		||||
        is_login: false,
 | 
			
		||||
    },
 | 
			
		||||
    getters: {
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    // 同步事件
 | 
			
		||||
    mutations: {
 | 
			
		||||
        // 更新用户信息
 | 
			
		||||
        updateUser(state, user){
 | 
			
		||||
            state.id = user.id;
 | 
			
		||||
            state.username = user.username;
 | 
			
		||||
            state.photo = user.photo;
 | 
			
		||||
            state.is_login = user.is_login;
 | 
			
		||||
        },
 | 
			
		||||
        // 更新用户 Token
 | 
			
		||||
        updateToken(state, token){
 | 
			
		||||
            state.token = token;
 | 
			
		||||
        },
 | 
			
		||||
        // 退出登录
 | 
			
		||||
        logout(state){
 | 
			
		||||
            state.id = "";
 | 
			
		||||
            state.username = "";
 | 
			
		||||
            state.photo = "";
 | 
			
		||||
            state.token = "";
 | 
			
		||||
            state.is_login = false;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    // 异步事件
 | 
			
		||||
    actions: {
 | 
			
		||||
        // 登录函数
 | 
			
		||||
        login(context, data){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: "http://localhost:3000/user/account/token/",
 | 
			
		||||
                type: "POST",
 | 
			
		||||
                data: {
 | 
			
		||||
                  username: data.username,
 | 
			
		||||
                  password: data.password,
 | 
			
		||||
                },
 | 
			
		||||
                success(resp) {
 | 
			
		||||
                //   console.log(resp.token, "\n成功了\n", resp.error_message);
 | 
			
		||||
                    if(resp.error_message === "success"){
 | 
			
		||||
                    /*
 | 
			
		||||
                        登录成功则将获取到的 resp 里的 token 传给 mutations 里的
 | 
			
		||||
                        updateToken 方法,对用户 token 信息进行更新
 | 
			
		||||
                    */
 | 
			
		||||
                        context.commit("updateToken", resp.token);
 | 
			
		||||
                        data.success(resp);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        data.error(resp);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                },
 | 
			
		||||
                error(resp) {
 | 
			
		||||
                  data.error(resp);
 | 
			
		||||
                },
 | 
			
		||||
              });
 | 
			
		||||
        },
 | 
			
		||||
        // 获取登录成功后的用户信息
 | 
			
		||||
        getinfo(context,data){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: "http://localhost:3000/user/account/info/",
 | 
			
		||||
                type: "GET",
 | 
			
		||||
                headers: {
 | 
			
		||||
                  Authorization:
 | 
			
		||||
                    "Bearer " + context.state.token,
 | 
			
		||||
                },
 | 
			
		||||
                success(resp) {
 | 
			
		||||
                    if(resp.error_message === "success"){
 | 
			
		||||
                        // 更新用户信息
 | 
			
		||||
                        context.commit("updateUser",{
 | 
			
		||||
                            ...resp,    // 解构 resp 中的内容
 | 
			
		||||
                            is_login: true, // 登录成功,将 is_login 置为 true
 | 
			
		||||
                        });
 | 
			
		||||
                        data.success(resp);   // 调用回调函数
 | 
			
		||||
                    } else {
 | 
			
		||||
                        data.error(resp);
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                error(resp) {
 | 
			
		||||
                  data.error(resp);
 | 
			
		||||
                },
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        logout(context){
 | 
			
		||||
            context.commit("logout");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    modules: {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								web/src/views/user/account/UserAccountLoginView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								web/src/views/user/account/UserAccountLoginView.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,98 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <ContentBase>
 | 
			
		||||
    <!-- justify-content-md-center 用于居中 -->
 | 
			
		||||
    <div class="row justify-content-md-center">
 | 
			
		||||
      <div class="col-3">
 | 
			
		||||
        <!-- 定义登录表单 @submita="login" 表示表单提交时触发 login 函数; submit.prevent 用于阻止 submit 的默认提交行为,
 | 
			
		||||
             而是调用自己定义的 login 函数来实现提交行为
 | 
			
		||||
        -->
 | 
			
		||||
        <form @submit.prevent="login">
 | 
			
		||||
          <div class="mb-3">
 | 
			
		||||
            <label for="username" class="form-label">用户名</label>
 | 
			
		||||
            <!-- 使用 v-model 来绑定函数里的 username 变量 -->
 | 
			
		||||
            <input
 | 
			
		||||
              v-model="username"
 | 
			
		||||
              type="text"
 | 
			
		||||
              class="form-control"
 | 
			
		||||
              id="username"
 | 
			
		||||
              placeholder="请输入用户名"
 | 
			
		||||
            />
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="mb-3">
 | 
			
		||||
            <label for="password" class="form-label">密码</label>
 | 
			
		||||
            <input
 | 
			
		||||
              v-model="password"
 | 
			
		||||
              type="password"
 | 
			
		||||
              class="form-control"
 | 
			
		||||
              id="password"
 | 
			
		||||
              placeholder="请输入密码"
 | 
			
		||||
            />
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="error-message">{{ error_message }}</div>
 | 
			
		||||
          <!-- float-start 左布局, float-end 右布局 -->
 | 
			
		||||
          <!-- type="submit" 提交类型 -->
 | 
			
		||||
          <button type="submit" class="btn btn-primary btn-sm float-center">登录</button>
 | 
			
		||||
        </form>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </ContentBase>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import ContentBase from "../../../components/ContentBase.vue";
 | 
			
		||||
import { useStore } from "vuex";
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import router from "../../../router/index";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  components: {
 | 
			
		||||
    ContentBase,
 | 
			
		||||
  },
 | 
			
		||||
  setup: () => {
 | 
			
		||||
    const store = useStore();
 | 
			
		||||
    let username = ref("");
 | 
			
		||||
    let password = ref("");
 | 
			
		||||
    let error_message = ref("");
 | 
			
		||||
 | 
			
		||||
    const login = () => {
 | 
			
		||||
      error_message.value = "";
 | 
			
		||||
      // 如果触发,则调用 store/user.js 里定义的 login 函数
 | 
			
		||||
      store.dispatch("login", {
 | 
			
		||||
        username: username.value,
 | 
			
		||||
        password: password.value,
 | 
			
		||||
        success() {
 | 
			
		||||
          // 登录成功,首先更新用户信息
 | 
			
		||||
          store.dispatch("getinfo", {
 | 
			
		||||
            success() {
 | 
			
		||||
              // 登录成功,则跳转到首页
 | 
			
		||||
              router.push({ name: "home" });
 | 
			
		||||
              console.log(store.state.user);
 | 
			
		||||
            },
 | 
			
		||||
          });
 | 
			
		||||
        },
 | 
			
		||||
        error() {
 | 
			
		||||
          // console.log(resp);
 | 
			
		||||
          error_message.value = "用户名或密码错误";
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      username,
 | 
			
		||||
      password,
 | 
			
		||||
      error_message,
 | 
			
		||||
      login,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
div.error-message {
 | 
			
		||||
  color: red;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										15
									
								
								web/src/views/user/account/UserAccountRegisterView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								web/src/views/user/account/UserAccountRegisterView.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <ContentBase>注册</ContentBase>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import ContentBase from "../../../components/ContentBase.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  components: {
 | 
			
		||||
    ContentBase,
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user