Common solutions for single sign-on and Alibaba Cloud SMS service

1 Single Sign-On (SSO)

Three common ways:

1.1 The first type: session broadcast mechanism implementation (obsolete)

Concept: session replication, after a module logs in, the module session stores the user login information, and then copies the session to other modules to implement session broadcasting, so that all modules can share the session; Disadvantage: when there are many modules, the
session It needs to be copied multiple times, resulting in a waste of resources and memory

1.2 The second type: using cookie+redis to achieve

Concept: Log in to any module in the project, and put the data in redis and cookies after logging in.
1.2.1 redis+cookie to store user data
Step 1:
redis
key: unique random value (ip, user id, etc.)
value: store user login data
cookie
Put the unique key value in redis into the cookie
Step 2:
access the project When other modules in , send a request with a cookie, the server receives the request, obtains the cookie value, obtains the primary key stored in redis from the cookie, and queries the corresponding user data through the redis key. If the result is not empty, it means that logged in.

1.3 The third method: use token to realize

  1. Log in in a certain module of the project, generate a string (token token-containing user information) according to certain rules after logging in, and then return the string. The return method can be returned through cookies or through the address bar.
  2. Then go to visit other modules of the project, each visit carries the token token (with the token parameter in the address bar), the server gets the string (token token) from the address bar, and gets the user information according to the token, if the result is not empty , then you are already logged in.

2 JWT(Json Web Token)

Traditional login authentication methods:

2.1 session authentication

Concept: Because the http protocol itself is a stateless protocol, it means that after a user authenticates to the system using an account number and password, the next login request needs to be authenticated again. Because we cannot know which user made the request through the http protocol, if we want to know which user made the request, we need to save a piece of user information on the server (saved to the session), and then return the cookie value after the authentication is successful. Give the browser, then the user can bring the cookie value in the next request, and the server can identify which user sent the request, whether it has been authenticated, whether the login has expired, and so on.
Disadvantages: Because the session is stored in the server, for distributed applications, since the session is not shared, each microservice requires user authentication...

2.2 token authentication

Concept: This method is similar to the session method. The difference is that a token value is saved to redis. The token is generally a string of random characters (such as UUID), and the value is generally the user ID, and an expiration time is set. Bring the token in the request header every time you request a service. When the backend receives the token, check whether redis exists according to the token. If it exists, it means that the user has been authenticated. If the token does not exist, it will jump to the login interface to let the user log in again. Login Return a token value to the client after success.
The advantage is that multiple servers use redis to access tokens, and there is no problem of non-sharing, so it is easy to expand. The disadvantage is that each request needs to check redis, which will cause pressure on redis and increase the time consumption of the request. Each logged-in user must save a token in redis, which will also consume redis storage space.

2.3 JWT authentication

Token is to generate strings according to certain rules, and JWT is the general rule recommended by the official, and strings can be generated by using JWT rules.
The string generated by JWT contains three parts:
the first part: JWT header information, which is a Json object describing JWT metadata, for example:
{ "alg": "HS256", //algorithm "typ": "JWT" ​​// Token type } The second part: Payload, in addition to containing the data (user information) that needs to be passed, there are seven default fields for selection. { //Default field "sub": "Subject 123", //Custom field "name": "java technology lover", "isAdmin": "true", "loginTime": "2021-12-05 12: 00:03” } The third part: the signature (anti-counterfeiting mark) first needs to specify a secret, which is only saved in the server and guaranteed not to be known to other users. Then use the algorithm specified by the Header to calculate the Header and Payload, and then get a signature hash, which is the Signature. So how to verify it? You can use the first two sections of the JWT to calculate a signature value with the same set of hash algorithms and the same secret, and then compare the calculated signature value with the third section of the received JWT. If they are the same, the authentication is passed.














2.3.1 Use of JWT

(1) Introduce dependencies:

 <!-- JWT-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
</dependency>

(2) Create a JWT tool class

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;

/**
 * @author
 */
public class JwtUtils {
    
    

    public static final long EXPIRE = 1000 * 60 * 60 * 24;
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

    public static String getJwtToken(String id, String nickname){
    
    

        String JwtToken = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setSubject("guli-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .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 {
    
    
            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;
            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 "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("id");
    }
}

3 Alibaba Cloud Short Message Service (SMS)

insert image description here

3.1 Sending and receiving SMS verification code based on Alibaba Cloud SMS service

If you want to use Alibaba Cloud's SMS service, you first need to activate the service, and you must have a signature and a template (the signature is the title of the SMS, usually an enterprise or related unit; the template is the specific content of the SMS). The service is charged, according to the number of charges, a few cents.
insert image description here

But at present, the application for signature and template needs to provide the company qualification certificate and the registered website address!
If you just want to test Alibaba Cloud's SMS service, such as sending and receiving SMS verification codes, Alibaba Cloud provides a free test API.
insert image description here

According to the SDK example provided by Alibaba Cloud, it can be integrated into our own code to realize the verification code method.
insert image description here

3.1.1 Alibaba Cloud SMS Verification Code Test API Example

Dependency import:

 <!--   阿里云短信服务测试API依赖     -->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>2.2.1</version>
        </dependency>
 <!--   单元测试     -->
     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.4.RELEASE</version>
        </dependency>

service:

package com.zhmsky.msmService.service;

/**
* @author zhmsky
* @date 2022/7/6 21:00
*/
public interface MsmService {
    
    
    
    /**
    * 阿里云发送短信验证码
    * @param phone 接收验证码的手机号
    * @param code 被发送的验证码
    * @return
    */
    String sendCodeMsg(String phone,String code);
    
}

serviceImpl:

package com.zhmsky.msmService.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.zhmsky.msmService.service.MsmService;
import org.springframework.stereotype.Service;

/**
 * @author zhmsky
 * @date 2022/7/6 21:01
 */
@Service
public class MsmServiceImpl implements MsmService {
    
    

    /**
     * 发送短信验证码
     * @param phone 手机号
     * @param code 被发送的验证码
     * @return
     */
    @Override
    public String sendCodeMsg(String phone, String code) {
    
    
        String checkCode="";
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tDfHQPQ5WA5dBkrfFxu", "eRID7ZigveAH7fMRKbCDq92jjRl68R");


        IAcsClient client = new DefaultAcsClient(profile);

        SendSmsRequest request = new SendSmsRequest();
        request.setSignName("阿里云短信测试");
        request.setTemplateCode("SMS_154950909");
        request.setPhoneNumbers(phone);
        request.setTemplateParam("{\"code\":\""+code+"\"}");

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

Interface test example:

import com.zhmsky.msmService.MsmApplication;
import com.zhmsky.msmService.service.MsmService;
import com.zhmsky.msmService.utils.RandomUtil;
import javafx.application.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author zhmsky
 * @date 2022/7/6 23:58
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MsmApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MainTest {
    
    

    @Autowired
    private MsmService msmService;

    @Test
    public void msgSendTest(){
    
    
        String sixBitRandom = RandomUtil.getSixBitRandom();
        String s = msmService.sendCodeMsg("你的手机号(需要在阿里云短信服务测试API绑定)", sixBitRandom);
        if("OK".equals(s)){
    
    
            System.out.println("发送成功!");
        }else {
    
    
            System.out.println("发送失败!");
        }
    }
}

You can view the corresponding request response body through the API documentation:
insert image description here

Guess you like

Origin blog.csdn.net/weixin_42194695/article/details/125650464