java | (三十八)登录服务、aly短信服务

单点登录及JWT

部分内容引用https://achang.blog.csdn.net/article/details/114419056

单点登录概念

单点登录(single sign on),简称SSO
应用于集群分布中,假设有多个服务器或多个tomcat,用户在一个服务器中登录,则其他的服务器就不需要登录(好比登录了QQ农场就不用登录QQ牧场)

另外,如果是单一服务器的化,直接用session实现登录更为方便,如

session.setAttribute(“user”,user)
session.getAttribute()

实现方式

1、session广播机制
即session的复制,但浪费资源,用比较少
过期时间设置:session默认过期时间30min,可修改这个来决定过期时间

2、cookie + redis实现
(1)在项目任意一个模块登录,然后将数据放到cookie和redis中
在redis中,key中存入随机唯一值(用户id、uid等),value中存放用户数据
(2)把redis中生成的key值放到cookie中
(3)访问项目其他模块,发送请求带着cookie,从cookie中的值拿到redis做查询,如果能查询出数据,则已经登录,否则没有登录
过期时间设置:可以设置redis中的过期时间

3、使用token实现
token(令牌):按照一定规则(加密)生成的字符串,字符串可以包含用户信息
(1)在项目某模块登录,然后按照规则生成字符串,把登录之后用户包含到生成字符串里面,把字符串返回(可以
通过cookie返回,或通过地址栏返回)
(2)再去访问项目其他模块,每次访问在地址栏带着生成字符串,在访问模块里面获取地址栏字符串,根据字符串获取用户信息,如果可以获取就是已登录

JWT

token是按照一定规则生成的字符串,JWT是规定好的规则,使用JWT可以生成字符串
组成如下:
在这里插入图片描述
java中实现
依赖pom.xml

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
</dependency>

JwtUtils.java(能看懂即可)

package com.liang.commonutils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

public class JwtUtils {
    
    

    //token过期时间
    public static final long EXPIRE = 1000 * 60 * 60 * 24;

    //秘钥,每个公司生成规则不一样
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

    //生成token字符串方法
    public static String getJwtToken(String id, String nickname) {
    
    
        String JwtToken = Jwts.builder()
                //设置jwt头信息,红色部分,内容固定,不需要改
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")

                .setSubject("guli-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))//设置过期时间

                //设置token主体部分,存储用户信息,可设置多个值
                .claim("id", id)
                .claim("nickname", nickname)

                //设置签名哈希(防伪标志)
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * 判断token是否存在与有效
     *
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
    
    
        if (StringUtils.isEmpty(jwtToken)) return false;
        try {
    
    
            //根据设置的防伪码解析token
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断token是否存在与有效
     *
     * @param request
     * @return
     */
    public static boolean checkToken(HttpServletRequest request) {
    
    
        try {
    
    
            String jwtToken = request.getHeader("token");
            if (StringUtils.isEmpty(jwtToken)) return false;
            //根据设置的防伪码解析token
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取会员id
     *
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
    
    
        String jwtToken = request.getHeader("token");
        if (StringUtils.isEmpty(jwtToken)) return "";
        //根据设置的防伪码解析token,获取对象
        Jws<Claims> claimsJws =
                Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        //获取token有效载荷【用户信息】
        Claims claims = claimsJws.getBody();
        return (String) claims.get("id");
    }
}

aly短信服务

建立相关模块并配置

创建模块service-msm,创建相关controller及service等文件夹
在这里插入图片描述
配置application.properties文件,将数据库信息、redis信息等配置好

# 用于aly短信服务

# 服务器端口
server.port=8005

# 服务名
spring.application.name=service-msm

#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

# nacos注册中心
spring.cloud.nacos.discovery.server-addr= localhost:8848

#配置mapper xml文件的路径
#mybatis-plus.mapper-locations=classpath:com/liang/msmservice/mapper/xml/*.xml

#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# redis

spring.redis.host=192.168.19.***
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#spring.redis.password=你设置的redis密码,没有可以不写
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

# mysql数据库连接
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=****
#环境测试:dev,test,prod
spring.profiles.active=dev

实现功能

在aly中开通服务(服务名称叫:短信服务),并申请
在这里插入图片描述
不过现在是企业才能申请了,所以这里使用aly的测试版
在这里插入图片描述
程序可看里面的示例代码
建立可以生成码的类:

package com.liang.msmservice.utils;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

public class RandomUtil {
    
    

    private static final Random random = new Random();

    private static final DecimalFormat fourdf = new DecimalFormat("0000");

    private static final DecimalFormat sixdf = new DecimalFormat("000000");

    //生成4位随机数
    public static String getFourBitRandom() {
    
    
        return fourdf.format(random.nextInt(10000));
    }

    //生成6位随机数
    public static String getSixBitRandom() {
    
    
        return sixdf.format(random.nextInt(1000000));
    }

    /**
     * 给定数组,抽取n个数据
     * @param list
     * @param n
     * @return
     */
    public static ArrayList getRandom(List list, int n) {
    
    

        Random random = new Random();

        HashMap<Object, Object> hashMap = new HashMap<Object, Object>();

        // 生成随机数字并存入HashMap
        for (int i = 0; i < list.size(); i++) {
    
    
            int number = random.nextInt(100) + 1;
            hashMap.put(number, i);
        }

        // 从HashMap导入数组
        Object[] robjs = hashMap.values().toArray();
        ArrayList r = new ArrayList();

        // 遍历数组并打印数据
        for (int i = 0; i < n; i++) {
    
    
            r.add(list.get((int) robjs[i]));
            System.out.print(list.get((int) robjs[i]) + "\t");
        }
        System.out.print("\n");
        return r;
    }
}

然后根据aly的示例代码进行修改,这里需要导入相关依赖

<!--        用于阿里云短信测试示例代码-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>2.2.1</version>
        </dependency>

controller.java

    @Autowired
    public MsmService msmService;

    //发送短信方法
    @GetMapping("sent/{phone}")
    public R sendMsm(@PathVariable String phone){
    
    
        //验证码的值是程序设计的
        String code = RandomUtil.getFourBitRandom();
        Map<String,Object> map = new HashMap<>();
        map.put("code",code);

        boolean isSend = msmService.send(map,phone);
        if(isSend){
    
    
            return R.ok();
        }else{
    
    
            return R.error().message("发送短信失败!");
        }
    }

Service.java

@Override
    //发送短信方法
    public boolean send(Map<String, Object> map, String phone) {
    
    
        System.out.println(Sample.keyId+"," + Sample.keySecret);
        DefaultProfile profile = DefaultProfile.getProfile("cn-shanghai",Sample.keyId,Sample.keySecret);
        IAcsClient client = new DefaultAcsClient(profile);
        //登录平台
        SendSmsRequest request = new SendSmsRequest();
        request.setSignName("阿里云短信测试");
        request.setTemplateCode("SMS_154950909");
        request.setPhoneNumbers(phone);
        String code = (String)map.get("code");
        request.setTemplateParam("{\"code\":\"" + code + "\"}");

        try {
    
    
            SendSmsResponse response = client.getAcsResponse(request);
            System.out.println(new Gson().toJson(response));
        } catch (ServerException e) {
    
    
            e.printStackTrace();
            return false;
        } catch (ClientException e) {
    
    
            System.out.println("ErrCode:" + e.getErrCode());
            System.out.println("ErrMsg:" + e.getErrMsg());
            System.out.println("RequestId:" + e.getRequestId());
            return false;
        }
        return true;
    }

这里的keyId和keySecret就是阿里云里面的,上述代码的Sample是自建类,就不列出来了,还有接口部分就省略不贴了。
在swagger进行测试:
在这里插入图片描述

不久后手机收到信息,成功

猜你喜欢

转载自blog.csdn.net/weixin_42953201/article/details/123805735