Learning notes of Shangsi Valley grain college 9 -- front desk user login, registration and integration jwt

Keywords: Java Spring Boot Spring Cloud Project

User login service

Single sign on (SSO) for short. Users only need to log in once to access all mutually trusted application systems

Three common ways of single sign on

  1. Implementation of session broadcast mechanism
  2. Using redis+cookie
  3. Using token to implement

Implementation of session broadcast mechanism

In fact, it is session replication. After logging in from one module, it is stored in the session and copied to other modules, but replication will consume resources
Suitable for projects with small number of modules

Using redis+cookie

After any module in the project logs in, the data is stored in two places
1.redis in key: generates unique random values (is, user id, etc.), and in value: user data
2.cookie: put the key value generated in redis into the cookie

Visit other modules of the project, send requests, send with cookies, obtain cookie values, and do things with cookies,
Get the value from the cookie, query in redis, and query according to the key. If the data is queried, log in

Using token to implement

Log in to a module of the project. After logging in, generate a string according to certain rules, include the logged in user in the generated string, and return the string
1. The string can be returned through a cookie
2. Support can be returned through the address bar

When accessing other modules of the project, the generated string is carried in the address bar every time. In the access module, you obtain the address bar string and obtain the user information according to the string. If you obtain it, you log in

In common_ Add jwt tool dependency in utils module

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

Create JWT tool class

package com.atguigu.commonutils.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;

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

/**
 * @author helen
 * @since 2019/10/16
 */
public class JwtUtils {

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

    //Method of generating token string
    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)//Set the token subject part to store user information
                .claim("nickname", nickname)
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * Judge whether the token exists and is valid
     * @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;
    }

    /**
     * Judge whether the token exists and is valid
     * @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;
    }

    /**
     * Get the member id according to the token
     * @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");
    }
}


New SMS micro service

Create a sub module service MSM under the service module

Create controller and service code

Startup class

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan("com.atguigu")
public class MsmApplication {
    public static void main(String[] args) {
        SpringApplication.run(MsmApplication.class,args);
    }
}

configuration file

# Service port
server.port=8005
# service name
spring.application.name=service-msm

# mysql database connection
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/gulischool?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

# Environment settings: dev, test, prod
spring.profiles.active=dev

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

spring.redis.host=123.57.252.81
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
#Maximum blocking waiting time (negative number indicates no limit)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
#Minimum idle

#Returns the global time format of json
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8


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

Introducing dependency in pom of service MSM

	<dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
        </dependency>
    </dependencies>

Write controller and send SMS according to mobile phone number

Generate verification code tool class

package com.atguigu.msmservice.utils;

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

/**
 * Get random number
 * 
 * @author qianyi
 *
 */
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");

	public static String getFourBitRandom() {
		return fourdf.format(random.nextInt(10000));
	}

	public static String getSixBitRandom() {
		return sixdf.format(random.nextInt(1000000));
	}

	/**
	 * Given an array, extract n data
	 * @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>();

		// Generate random numbers and store them in HashMap
		for (int i = 0; i < list.size(); i++) {

			int number = random.nextInt(100) + 1;

			hashMap.put(number, i);
		}

		// Importing arrays from HashMap
		Object[] robjs = hashMap.values().toArray();

		ArrayList r = new ArrayList();

		// Traverse the array and print the data
		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;
	}
}

@RestController
@CrossOrigin
@RequestMapping("/edumsm/msm")
public class MsmController {

    @Autowired
    private MsmService msmService;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    //Method of sending short message
    @GetMapping("send/{phone}")
    public ResultVo sendMsm(@RequestParam String phone){
        //Get the verification code from redis first. If you get the verification code, it will be returned directly
        String code= redisTemplate.opsForValue().get(phone);
        if(!StringUtils.isEmpty(code)){
            return ResultVo.ok();
        }
        //If redis can't get it, send it to Alibaba cloud

        //Generate random values and send them to Alibaba cloud
        code= RandomUtil.getFourBitRandom();
        HashMap<Object, Object> param = new HashMap<>();
        param.put("code",code);
        //Call service to send SMS
        boolean isSend=msmService.send(param,phone);
        if(isSend){
            redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES);
            return ResultVo.ok();
        }
        else{
            return ResultVo.error().message("SMS sending failed");
        }


    }
}

@Override
    public boolean send(HashMap<Object, Object> param, String phone) {
        if(StringUtils.isEmpty(phone)){
            return false;
        }
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "<accessKeyId>", "<accessSecret>");//AccessKey information of your account
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain("dysmsapi.aliyuncs.com");//Service access address of SMS service
        request.setSysVersion("2017-05-25");//Version number of the API
        request.setSysAction("SendSms");//The name of the API
        request.putQueryParameter("PhoneNumbers", "1503871****");//Mobile phone number to receive SMS
        request.putQueryParameter("SignName", "Special for Ali test");//SMS signature name
        request.putQueryParameter("TemplateCode", "SMS_209335004");//SMS template ID
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));//Actual value corresponding to SMS template variable
        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
            boolean success = response.getHttpResponse().isSuccess();
            return success;
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }

Login and registration

Create a sub module service UCenter under the service module

Generating code using a code generator

Create ucenter_member table

configuration file

# Service port
server.port=8006
# service name
spring.application.name=service-ucenter

# Environment settings: dev, test, prod
spring.profiles.active=dev

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# mysql database connection
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/gulischool?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

spring.redis.host=123.57.252.81
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
#Maximum blocking waiting time (negative number indicates no limit)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
#Minimum idle

#Returns the global time format of json
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

#The path to the configuration mapper xml file
mybatis-plus.mapper-locations=classpath:com/atguigu/educenter/mapper/xml/*.xml

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

Create startup class

@SpringBootApplication
@ComponentScan({"com.atguigu"})
@MapperScan("com.atguigu.educenter.mapper")
public class UcenterApplication {
    public static void main(String[] args) {
        SpringApplication.run(UcenterApplication.class,args);
    }
}

RegisterVo is used for data encapsulation

@Data

@ApiModel(value="Registered object", description="Registered object")
public class RegisterVo {

    @ApiModelProperty(value = "nickname")
    private String nickname;

    @ApiModelProperty(value = "cell-phone number")
    private String mobile;

    @ApiModelProperty(value = "password")
    private String password;

    @ApiModelProperty(value = "Verification Code")
    private String code;
}

Create a controller and write login and registration methods

@RestController
@CrossOrigin
@RequestMapping("/educenter/member")
public class UcenterMemberController {

    @Autowired
    private UcenterMemberService memberService;

    //Sign in
    @PostMapping("/login")
    public ResultVo login(@RequestBody UcenterMember member){
        //Call the service method to log in
        //Return the token value, which is generated using jwt
        String token=memberService.login(member);
        return ResultVo.ok().data("token",token);
    }

    //register
    @PostMapping("register")
    public ResultVo register(@RequestBody RegisterVo registerVo){
        memberService.register(registerVo);
        return ResultVo.ok();

    }

    //Obtain user information according to the token
    @GetMapping("getMemberInfo")
    public ResultVo getMemberInfo(HttpServletRequest request){
        //Call the jwt tool class method, get the header information according to the request object, and return the user id
        String id = JwtUtils.getMemberIdByJwtToken(request);
        //Query database user id to obtain user information
        UcenterMember member = memberService.getById(id);

        return ResultVo.ok().data("userIno",member);
    }
}

Create service interface and implementation class

@Service
public class UcenterMemberServiceImpl extends ServiceImpl<UcenterMemberMapper, UcenterMember> implements UcenterMemberService {


    @Autowired
    private RedisTemplate<String,String>  redisTemplate;
    //Sign in
    @Override
    public String login(UcenterMember member) {
        String mobile = member.getMobile();
        String password = member.getPassword();

        //Judge whether the mobile phone number and password are empty
        if(StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)){
            throw new GuliException(20001,"Login failed");
        }
        //Judge whether the mobile phone number is correct
        QueryWrapper<UcenterMember> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile",mobile);
        UcenterMember ucenterMember = baseMapper.selectOne(queryWrapper);
        //Judge whether the query object is empty
        if(ucenterMember==null){
            //I don't have this phone number
            throw new GuliException(20001,"Login failed");

        }
        //Judge password
        //Encrypt the entered password and compare it with the database password
        if(!MD5.encrypt(password).equals(ucenterMember.getPassword())){
            throw new GuliException(20001,"Login failed");
        }

        //Judge whether the user is disabled
        if(ucenterMember.getIsDisabled()){
            throw new GuliException(20001,"Login failed");
        }

        //Login succeeded
        //Generate token string and use jwt tool class
        String jwtToken = JwtUtils.getJwtToken(ucenterMember.getId(), ucenterMember.getNickname());

        return jwtToken;
    }

    //register
    @Override
    public void register(RegisterVo registerVo) {
        //Get registered data
        String code=registerVo.getCode();//Verification Code
        String mobile = registerVo.getMobile(); //cell-phone number
        String nickname = registerVo.getNickname(); //nickname
        String password = registerVo.getPassword(); //password

        //Non null judgment
        if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password) || StringUtils.isEmpty(code)||StringUtils.isEmpty(nickname)){
            throw new GuliException(20001,"login has failed");
        }

        //Judgment verification code
        //Get redis verification code
        String rediscode = redisTemplate.opsForValue().get(mobile);
        if(!code.equals(rediscode)){
            throw new GuliException(20001,"login has failed");
        }

        //Judge whether the mobile phones are duplicate. If the same mobile phone number exists in the table, it will not be added
        QueryWrapper<UcenterMember> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile",mobile);
        Integer count = baseMapper.selectCount(queryWrapper);
        if(count>0){
            throw new GuliException(20001,"login has failed");
        }

        UcenterMember ucenterMember = new UcenterMember();
        ucenterMember.setMobile(mobile);
        ucenterMember.setNickname(nickname);
        ucenterMember.setPassword(MD5.encrypt(password));
        ucenterMember.setIsDisabled(false);
        ucenterMember.setAvatar("https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        baseMapper.insert(ucenterMember);
    }


}

Posted by kmarsh on Mon, 04 Oct 2021 14:46:15 -0700