个人博客 毕业设计6-密码加密和微服务鉴权JWT

一、BC加密(管理员例子)

1、准备工作

	  <dependency>
		  <groupId>org.springframework.boot</groupId>
		  <artifactId>spring-boot-starter-security</artifactId>
	  </dependency>

配置类

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    
    
        http
                //这个必写
                .authorizeRequests()
                //所有请求路径都运行
                .antMatchers("/**").permitAll()
                //所有请求都要经过验证
                .anyRequest().authenticated()
                //降低安全级别
                .and().csrf().disable();
    }
}

在启动类中加入bean

@SpringBootApplication
public class UserApplication {
    
    

	public static void main(String[] args) {
    
    
		SpringApplication.run(UserApplication.class, args);
	}

	@Bean
	public BCryptPasswordEncoder bCryptPasswordEncoder(){
    
    
		return new BCryptPasswordEncoder();
	}
}

2、新增管理员加密

这个就简单啦,在管理员注册加密就行
在这里插入图片描述

@Service
public class AdminService {
    
    

	@Autowired
	private BCryptPasswordEncoder bCryptPasswordEncoder;

	public void add(Admin admin) {
    
    
		admin.setId( idWorker.nextId()+"" );
		admin.setState("1");
		//BC加密
		admin.setPassword(bCryptPasswordEncoder.encode(admin.getPassword()));
		adminDao.save(admin);
	}
}
  • admin.setPassword(bCryptPasswordEncoder.encode(admin.getPassword())); 进行BC加密
    在这里插入图片描述
    在这里插入图片描述

3、管理员登陆校验

一般来说,要登陆进去了,然后设置session或者token值,让前后端都知道通过验证了。
在这里插入图片描述

public interface AdminDao extends JpaRepository<Admin,String>,JpaSpecificationExecutor<Admin>{
    
    

    public Admin findByLoginname(String loginname);
}

service

	public Admin login(Admin admin) {
    
    
		Admin adminLogin = adminDao.findByLoginname(admin.getLoginname());
		//matches(输入的密码,数据库中的密码),可以让两个相匹配。因为密码通过BC每次都会不一样
		if (adminLogin!=null && bCryptPasswordEncoder.matches(admin.getPassword(),adminLogin.getPassword())){
    
    
			//数据库中找得到,然后密码一致,返回数据库中的admin
			return adminLogin;
		}
		//否则就返回null
		return null;
	}
	@PostMapping(value = "login")
	public Result login(@RequestBody Admin admin){
    
    
		Admin login = adminService.login(admin);
		if (login!=null){
    
    
			//这里还要写session或者token,后续
			return new Result(true,StatusCode.OK,"登陆成功");
		}else return new Result(false,StatusCode.LOGINERROR,"用户名或者密码错误");
	}
  • BC加密,每一次传过来同样的字符串都会生成不同的加密字符串,所有对比两者是否相同无法比较。
  • 但是BC提供了一个方法我们进行匹配:BC类.matches(输入的密码,数据库中的密码)

在这里插入图片描述

4、用户登陆注册

和上面的一样

注册

UserService

	@Autowired
	private BCryptPasswordEncoder bCryptPasswordEncoder;
	
	public void register(User user, String code) {
    
    
	//..
		user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
	//..
	}

登陆

在这里插入图片描述

public interface UserDao extends JpaRepository<User,String>,JpaSpecificationExecutor<User>{
    
    
	public User findByMobile(String mobile);
}

service

	public User login(User user){
    
    
		User userLogin = userDao.findByMobile(user.getMobile());
		if (userLogin!=null && bCryptPasswordEncoder.matches(user.getPassword(),userLogin.getPassword())){
    
    
			return userLogin;
		}
		return null;
	}

controller

	@PostMapping("login")
	public Result login(@RequestBody User user){
    
    
		User login = userService.login(user);
		if (login!=null){
    
    
			return new Result(true,StatusCode.OK,"登陆成功");
		}else return new Result(false,StatusCode.LOGINERROR,"用户名或者密码错误");
	}

在这里插入图片描述
在这里插入图片描述

二、常见的认证机制

1、HTTP Basic Auth

这是最原始的认证方式,输入username和password配合 RESTful API使用过。但是会把账号密码暴露,所以现在没什么人用这个。

2、Cookie Auth

这是就是登陆后存储一个session或者cookie,让前端知道已经登陆了。在关闭的时候cookie删除。但是安卓和IOS中没有cookie,不支持移动端。众所周知存储在cookie中是不安全的,会通过修改cookie和csrf攻击。

3、OAuth

第三方登陆,例如微信扫码登陆一样,无需输入任何账号和密码。
目前很流行,适用于个人消费者类的互联网产品如社交类APP,但是不适合拥有自有认证权限管理的企业应用

4、Token Auth

我们用的就是这个技术。
令牌登陆,登陆服务端生成一个令牌,给前端。前端收到后就知道登陆了。

流程:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向 客户端返回请求的数据

优势:

  • 支持跨域访问
  • 无状态:token机制在服务端不需要存储session,不需要每一个用户都要记录,降低数据库压力
  • CSRF:不依赖cookie,所以不需要进行SCRF防范

三、基于JWT的Token认证机制实现

JWT(JSON Web Token)

1、组成

其实际上就是一个字符串,由头部,载荷,签名三部分组成。

其中头部记录基本信息。载荷记录重要的用户信息之类的。

然后进行BASE64编码(因为JWT只支持BASE64编码)。将头部和载荷进行BASE64编码后连接成字符串,然后通过头部中声明的加密方式(HS256)通过加盐组合加密,构成签名。

然后将BASE64之后的头部和载荷,还有签名,通过.进行连接,组成了JWT

头部

用于描述改JWT的基本信息

{"typ":"JWT","alg":"HS256"}

表明该类型是JWT,签名算法用HS256算法(哈希256)
然后进行BASE64编码eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

载荷

标准中注册的声明(推荐但不强制)

  • iss: jwt签发者
  • sub: jwt所面向的用户 ,一般写用户名
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
    比如定义载荷{"sub":"1234567890","name":"John Doe","admin":true},BASE64后eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

签证

加密后的头部和载荷用.连接的字符串,通过HS256加密方式进行加盐组合(该盐一般公司内定,不让别人知道)加密

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

HS256加密TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

JWT

加起来就是
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
这么一串东西就是JWT

四、 Java的JJWT实现JWT

JJWT(Java JSON Web Token)
需要导包

        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

1、快速入门

1)Jwt创建测试

public class CreateJwtTest {
    
    
    public static void main(String[] args) {
    
    
        JwtBuilder jwtBuilder = Jwts.builder()
                .setId("666")//ID
                .setSubject("小强")//用户名
                .setIssuedAt(new Date())//创建时间
                //signWith(加密算法,加密盐)
                .signWith(SignatureAlgorithm.HS256, "tensquare");
        //jwtBuilder.compact() 转化为String类型
        System.out.println(jwtBuilder.compact());
    }
}
  • setxxx(),这就是载荷的那些东西,本来是填JSON但现在用Java写,自动转换
  • signWith头部,第一参数是加密方式,第二参数是加密盐值,一般这个加密盐值不让别人知道
  • 然后签名就会自动生成了

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiLlsI_lvLoiLCJpYXQiOjE2MDY0NjQ2NDN9.rBjStx3MRdZ4bfOcu2iTnvnUE3TZ_0Oq7rtaMPCZ_yM

这就是三部分的东西,生成一个JWT了,然后每一次结果会不一样,因为加入了时间

2)解析Jwt

public class ParseJwtTest {
    
    
    public static void main(String[] args) {
    
    
        String Jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiLlsI_lvLoiLCJpYXQiOjE2MDY0NjUwODl9.eK0m9-39DF_fOjzgMqOQdaSiu9-uZmncYSn404JKAkY";

        Claims claims = Jwts.parser()//开始解析
                .setSigningKey("tensquare")//加密盐
                .parseClaimsJws(Jwt)//那串JWT
                .getBody();

        System.out.println("用户ID:"+claims.getId());
        System.out.println("用户名:"+claims.getSubject());
        System.out.println("登陆时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getIssuedAt()));
    }
}
  • Claims 类似一个Map

用户ID:666
用户名:小强
登陆时间:2020-11-27 16:18:09

3)JWT过期校验

public class CreateJwtTest {
    
    
    public static void main(String[] args) {
    
    

        //获取当前时间戳
        long now = System.currentTimeMillis();
        //过期时间,加一分钟
        long exp = now + 1*60*1000;

        JwtBuilder jwtBuilder = Jwts.builder()//开始构建
                .setId("666")//ID
                .setSubject("小强")//用户名
                .setIssuedAt(new Date(now))//创建时间
                .setExpiration(new Date(exp))//过期时间
                //signWith(加密算法,加密盐)
                .signWith(SignatureAlgorithm.HS256, "tensquare");

        //jwtBuilder.compact() 转化为String类型
        System.out.println(jwtBuilder.compact());
    }
}
public class ParseJwtTest {
    
    
    public static void main(String[] args) {
    
    
        String Jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiLlsI_lvLoiLCJpYXQiOjE2MDY0Njc4MzgsImV4cCI6MTYwNjQ2Nzg5OH0.X-20hF-1xqrv6KZ0OLyUYrHrTTGTrbpCIkWI0tHV15w";

        Claims claims = Jwts.parser()//开始解析
                .setSigningKey("tensquare")//加密盐
                .parseClaimsJws(Jwt)//那串JWT
                .getBody();

        System.out.println("用户ID:"+claims.getId());
        System.out.println("用户名:"+claims.getSubject());
        System.out.println("登陆时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getIssuedAt()));
        System.out.println("过期时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getExpiration()));
    }
}

用户ID:666
用户名:小强
登陆时间:2020-11-27 17:03:58
过期时间:2020-11-27 17:04:58

如果时间过期了

Exception in thread "main" io.jsonwebtoken.ExpiredJwtException: JWT expired at 2020-11-27T17:04:58Z. Current time: 2020-11-27T17:05:44Z, a difference of 46265 milliseconds.  Allowed clock skew: 0 milliseconds.
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:385)
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481)
	at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:541)
	at jwt.ParseJwtTest.main(ParseJwtTest.java:14)

4)自定义创建键值

public class CreateJwtTest {
    
    
    public static void main(String[] args) {
    
    

        //获取当前时间戳
        long now = System.currentTimeMillis();
        //过期时间,加一分钟
        long exp = now + 1*60*1000;

        JwtBuilder jwtBuilder = Jwts.builder()//开始构建
                .setId("666")//ID
                .setSubject("小强")//用户名
                .setIssuedAt(new Date(now))//创建时间
                .setExpiration(new Date(exp))//过期时间
                .claim("roles","user")//添加自定义键值
                //signWith(加密算法,加密盐)
                .signWith(SignatureAlgorithm.HS256, "tensquare");

        //jwtBuilder.compact() 转化为String类型
        System.out.println(jwtBuilder.compact());
    }
}
public class ParseJwtTest {
    
    
    public static void main(String[] args) {
    
    
        String Jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiLlsI_lvLoiLCJpYXQiOjE2MDY0NjgyNzAsImV4cCI6MTYwNjQ2ODMzMCwicm9sZXMiOiJ1c2VyIn0.yWPMXOPcxPYvbjwkmOSUdzpGZJXpOsPJaqNjMHwpsFw";
        Claims claims = Jwts.parser()//开始解析
                .setSigningKey("tensquare")//加密盐
                .parseClaimsJws(Jwt)//那串JWT
                .getBody();

        System.out.println("用户ID:"+claims.getId());
        System.out.println("用户名:"+claims.getSubject());
        System.out.println("登陆时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getIssuedAt()));
        System.out.println("过期时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getExpiration()));
        System.out.println("用户角色:"+claims.get("roles"));//claims.get("下标")
    }
}

用户ID:666
用户名:小强
登陆时间:2020-11-27 17:11:10
过期时间:2020-11-27 17:12:10
用户角色:user

五、微服务鉴权

1、准备

记得tensquare_common导jjwt包
在tensquare_commom中添加工具类

@ConfigurationProperties("jwt.config")
@Data
public class JwtUtil {
    
    

    private String key ;

    private long ttl ;//一个小时

    /**
     * 生成JWT
     *
     * @param id 用户ID
     * @param subject 用户名
     * @param roles 角色名
     * @return JWT字符串
     */
    public String createJWT(String id, String subject, String roles) {
    
    
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                .signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
        if (ttl > 0) {
    
    
            builder.setExpiration( new Date( nowMillis + ttl));
        }
        return builder.compact();
    }

    /**
     * 解析JWT
     * @param jwtStr
     * @return
     */
    public Claims parseJWT(String jwtStr){
    
    
        return  Jwts.parser()
                //key就是盐值
                .setSigningKey(key)
                //JWT字符串
                .parseClaimsJws(jwtStr)
                .getBody();
    }

}

写好工具类后,在user模块修改yml和注入Bean

jwt:
  config:
    #    盐值
    key: tensquare
    #    一个小时
    ttl: 3600000
	@Bean
	public JwtUtil jwtUtil(){
    
    
		return new JwtUtil();
	}

2、管理员控制类获取token

然后在admin控制类修改

@RestController
@CrossOrigin
@RequestMapping("/admin")
public class AdminController {
    
    

	@Autowired
	private AdminService adminService;

	@Autowired
	private JwtUtil jwtUtil;
	
	@PostMapping(value = "login")
	public Result login(@RequestBody Admin admin){
    
    
		Admin login = adminService.login(admin);
		if (login!=null){
    
    
			//这里写token
			//生成token
			String token = jwtUtil.createJWT(login.getId(), login.getLoginname(), "admin");//角色写死admin了
			Map<String,Object> map = new HashMap<>();
			map.put("token",token);
			map.put("name",login.getLoginname());
			//角色写死admin了
			map.put("role","admin");

			return new Result(true,StatusCode.OK,"登陆成功",map);
		}else return new Result(false,StatusCode.LOGINERROR,"用户名或者密码错误");
	}

在这里插入图片描述
这里给名字和权限是为了方便。

3、删除用户功能鉴权

删除用户,必须要又管理员权限,否则不能删除
把token放在body中不安全(我也不知道为啥不安全。。。)。所以把token放在消息头里面好一点
在这里插入图片描述
那些Response Headers就是消息头。

前后端约定:前端请求微服务时需要添加头信息Authorization,内容为Bearer+空格+token

userService

@Service
public class UserService {
    
    
 
	//消息头
	@Autowired
	private HttpServletRequest request;

	@Autowired
	private JwtUtil jwtUtil;

	/**
	 * 删除需要具有管理员权限,权限放在消息头里面  Bearer+空格+token
	 * 删除
	 * @param id
	 */
	public void deleteById(String id) {
    
    
		//获取key为Authorization的消息头
		String authHeader = request.getHeader("Authorization");

		//如果没有找到该消息头
		if (authHeader==null){
    
    
			throw new RuntimeException("权限不足");
		}
		//不以"Bearer "开头的话
		if (!authHeader.startsWith("Bearer ")){
    
    
			throw new RuntimeException("权限不足");
		}
		//从第7位直最后一位开始判断token,因为"Bearer "占7位,从0开始的
		String token = authHeader.substring(7);

		try {
    
    
			//将token转义
			Claims claims = jwtUtil.parseJWT(token);

			//得到角色
			String roles = (String) claims.get("roles");
			//如果角色为空或者角色不是admin,异常
			if (roles==null || !roles.equals("admin")){
    
    
				throw new RuntimeException("权限不足");
			}
		}catch (Exception e){
    
    
			//有啥异常都说权限不足了
			throw new RuntimeException("权限不足");
		}
		//如果到这里都没错误的话
		userDao.deleteById(id);
	}

测试一下错误的
在这里插入图片描述
测试一下正确的
在这里插入图片描述

六、拦截器方式实现token鉴权

一个删除功能,就要写这么长得token鉴权代码了,其他得地方也是复制粘贴,还不如做拦截器好点。
这个拦截器呢,也不是真的拦截啦(还没到之后的访问无权限一步)。对所有请求路径进行判断,但都会放行。如果有令牌就记录在头消息,没有就不记录。所以只是做个token处理

1、测试拦截器

好久没做拦截器了,试下
拦截器类

//JWT令牌拦截器,对所有进行判断,但都会放行。如果有令牌就记录在头消息,没有就不记录
@Component
public class JwtInterceptor implements HandlerInterceptor {
    
    

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        System.out.println("该路径经过了拦截器");
        return true;//都放行
    }
}

配置类,注册拦截器

//拦截器配置类,进行拦截器注册
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
    
    

    @Autowired
    JwtInterceptor jwtInterceptor;

    //添加拦截器
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(jwtInterceptor)//注册拦截器
                .addPathPatterns("/**")//对所有路径拦截
                .excludePathPatterns("/**/login/**");//但对登陆不拦截
    }
}

localhost:9008/user查看全部用户,后台显示

该路径经过了拦截器

那么接下来就是在拦截器类中写代码了

2、拦截器验证token

//JWT令牌拦截器,对所有进行判断,但都会放行。如果有令牌就记录在头消息,没有就不记录
@Component
public class JwtInterceptor implements HandlerInterceptor {
    
    

    @Autowired
    JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        String header = request.getHeader("Authorization");//获取头信息

        //如果真的有这个头消息,就进行判定。如果有这个令牌,并且通过了一些列判断,再设置一个消息头键值claims_xxx
        // 然后service那边就getAttribute(claims_xxx)进行判断,而不是还是用Authorization判断
        if (header!=null && !"".equals(header)){
    
    
            //如果头消息以Bearer 开头的话
            if (header.startsWith("Bearer ")){
    
    
                String token = header.substring(7);
                try {
    
    
                    //将token转义
                    Claims claims = jwtUtil.parseJWT(token);

                    //得到角色
                    String roles = (String) claims.get("roles");
                    //判断角色是啥
                    if (roles!=null && roles.equals("admin")){
    
    
                        request.setAttribute("claims_admin",token);
                    }
                    if (roles!=null && roles.equals("user")){
    
    
                        request.setAttribute("claims_user",token);
                    }
                }catch (Exception e){
    
    
                    throw new RuntimeException("令牌有误");
                }
            }
        }

        return true;//都放行
    }
}

修改UserSerivce

	public void deleteById(String id) {
    
    
		//判断是否有claims_admin的消息头
		String token = (String) request.getAttribute("claims_admin");
		System.out.println(token);
		//如果为空
		if (token==null || "".equals(token)){
    
    
			throw new RuntimeException("权限不足");
		}

		userDao.deleteById(id);
	}

在这里插入图片描述
在这里插入图片描述

七、其他模块

完成了管理员登陆得到令牌,以及删除ID时需要令牌得到验证,以及拦截器。

然后其他模块也是复制粘贴就行

1、用户登陆添加令牌

@RestController
@CrossOrigin
@RequestMapping("/user")
public class UserController {
    
    

	@Autowired
	private JwtUtil jwtUtil;
	
	@PostMapping("login")
	public Result login(@RequestBody User user){
    
    

		User login = userService.login(user);
		if (login!=null){
    
    

			String token = jwtUtil.createJWT(login.getId(), login.getMobile(), "user");//角色写死admin了
			Map<String,Object> map = new HashMap<>();
			map.put("token",token);
			map.put("role","user");
			return new Result(true,StatusCode.OK,"登陆成功");
		}else return new Result(false,StatusCode.LOGINERROR,"用户名或者密码错误");
	}

2、其他模块添加yml,和添加JWT的Bean

JWT工具类都写在common中,但是盐什么的还没写

jwt:
 config:
   #    盐值
   key: tensquare
   #    一个小时
   ttl: 3600000
	@Bean
	public JwtUtil jwtUtil(){
    
    
		return new JwtUtil();
	}

3、其他模块添加拦截器

老复制粘贴了
JwtInterceptor和InterceptorConfig

4、在每一个需要权限的service层,添加token验证

比如什么添加问答,需要user权限
在这里插入图片描述

@Service
public class xxxService {
    
    

	//消息头
	@Autowired
	private HttpServletRequest request;

	@Autowired
	private JwtUtil jwtUtil;

	public void add(Problem problem) {
    
    

		//判断是否有claims_admin的消息头
		String token = (String) request.getAttribute("claims_user");//要么claims_user,要么claims_admin
		//如果为空
		if (token==null || "".equals(token)){
    
    
			throw new RuntimeException("权限不足");
		}

		problem.setId( idWorker.nextId()+"" );
		problemDao.save(problem);
	}

5、测试

未登录
在这里插入图片描述
登陆:
在这里插入图片描述
header和body不能一起截图
在这里插入图片描述
在这里插入图片描述

八、整个流程

注册:

  • 用户注册,后台随机生成6位数字,向redis缓存中保存一份,方便用户输入验证码时,从redis中获取数据进行对比。

  • 然后利用RabbitMQ,注册时生产消息,发送给队列sms。然后设置消息消费者,队列sms一收到消息,就进行业务操作:利用阿里云短信功能,接受到队列消息,给目标手机号发送验证码信息。

  • 用户手机接受到验证码后,输入个人信息和输入验证码。其中,密码用到BC加密(security包中)。后台接受数据后,从redis中查询对应的验证码。如果一样,则保存记录到MySQL,如果不一致,返回错误

登陆:

  • 用户输入账号与密码,密码采用自带的函数进行验证,如果密码正确,则返回一个token令牌
  • token具有时效性和权力性,执行任何增删改查操作都需要用到令牌。

增删改查操作

  • 先进行一个拦截器,除了登陆那一步不拦截,所有的都拦截。
  • 拦截器里面对所有请求都通行,但是都检查一下头消息中有没有带token(JWT)令牌。如果有,则将内容保留到一个新的头消息中;没有就没有,但也放行
  • 进行业务增删改查操作时,需要检查一下头消息中有没有验证后的token,如果有,则进行操作;如果没有,就返回错误

猜你喜欢

转载自blog.csdn.net/yi742891270/article/details/110205034