Halo开源项目(1.1)---登录模块具体方法

一.登录模块具体方法

  1. 根据loginParam获取User对象
    1. 发现userRepository类
    2. 观察DTO类 —> UserDTO为例
    3. 观察entity类 —> User
  2. 两步验证码验证, 需要在系统设置中开启
  3. 检查用户是否已经登录过了
  4. 返回一个随机生成的token, 成为json对象. ----> 储存至本地内存, 以保持登录

1.1 根据loginParam获取User对象

方法run.halo.app.service.impl.AdminServiceImpl#authenticate

@Override
@NonNull
public User authenticate(@NonNull LoginParam loginParam) {
    //判断输入的信息是否为空, 如果为空, 则输出message
    Assert.notNull(loginParam, "Login param must not be null");
	//根据loginParam获取用户名
    String username = loginParam.getUsername();

    String mismatchTip = "用户名或者密码不正确";

    final User user;

    try {
        // Get user by username or email 三目运算符
        user = Validator.isEmail(username) //username 判断是否为邮箱格式
            //若有效,则执行第一个, 无效则执行第二个
            ? userService.getByEmailOfNonNull(username) :
            userService.getByUsernameOfNonNull(username);
    } catch (NotFoundException e) {
        //有@Slf4j注解,可以直接调用log,控制台输出
        log.error("Failed to find user by name: " + username); 
        eventPublisher.publishEvent(
            new LogEvent(this, loginParam.getUsername(), LogType.LOGIN_FAILED,
                loginParam.getUsername()));

        throw new BadRequestException(mismatchTip);
    }
    //检查用户登录是否过期, 系统现在的时间和ex
    userService.mustNotExpire(user);

    //利用BCrypt加密算法,验证输入密码和数据库中的密码是否相同
    if (!userService.passwordMatch(user, loginParam.getPassword())) {
        // If the password is mismatch
        eventPublisher.publishEvent(
            new LogEvent(this, loginParam.getUsername(), LogType.LOGIN_FAILED,
                loginParam.getUsername()));

        throw new BadRequestException(mismatchTip);
    }

    return user;
}

getByEmailOfNonNull 方法:

run.halo.app.service.impl.UserServiceImpl#getByEmailOfNonNull

@Override
public User getByEmailOfNonNull(String email) {
    return getByEmail(email).orElseThrow(
        () -> new NotFoundException("The email does not exist").setErrorData(email));
}

进入getByEmail方法中

1.1.1 发现userRepository类

@Override
public Optional<User> getByEmail(String email) {
    return userRepository.findByEmail(email);
}

这里出现了userRepository

public interface UserRepository extends BaseRepository<User, Integer> {}

userRepository继承了BaseRepository, BaseRepository的父类是JpaRepository

@NoRepositoryBean
public interface BaseRepository<D, I> extends JpaRepository<D, I> {}

这里是利用了Spring Data JPA, 通过简单的注解和继承关系, 实现CRUD操作

即生成DTO类( DAO类).

1.1.2 观察DTO类 —> UserDTO为例

@Data //可以根据实体类, 自动生成相关的方法 ,如get set 等方法
@ToString //重写ToString方法
@EqualsAndHashCode  //重写EqualsAndHashCode方法
public class UserDTO implements OutputConverter<UserDTO, User> {

    private Integer id;

    private String username;

    private String nickname;

    private String email;

    private String avatar;

    private String description;

    private MFAType mfaType;

    private Date createTime;

    private Date updateTime;
}

1.1.3 观察entity类 —> User

@Data 
@Entity //JPA , 可以根据实体类, 在数据库中生成相应的表
@Table(name = "users") //表名
//子类加上@Data和@ToString(callSuper = true)两个注解, 父类也使用注解@Data
@ToString(callSuper = true) 
@EqualsAndHashCode(callSuper = true)
public class User extends BaseEntity {

    @Id //该变量为主键 
    @GeneratedValue(strategy = GenerationType.IDENTITY) //主键类型
    @Column(name = "id") //列名
    private Integer id;

    @Column(name = "username", length = 50, nullable = false) //列名 和 长度设置
    private String username;
    ...
}

1.2 两步验证码验证, 需要在系统设置中开启

1.3 检查用户是否已经登录过了

1.4 返回一个随机生成的token, 成为json对象.

----> 储存至本地内存, 以保持登录

return buildAuthToken(user);

run.halo.app.service.impl.AdminServiceImpl#buildAuthToken

根据user对象,生成相应的token

@NonNull
private AuthToken buildAuthToken(@NonNull User user) {
    Assert.notNull(user, "User must not be null");

    // Generate new token
    AuthToken token = new AuthToken();

    token.setAccessToken(HaloUtils.randomUUIDWithoutDash());
    token.setExpiredIn(ACCESS_TOKEN_EXPIRED_SECONDS);  //24小时
    token.setRefreshToken(HaloUtils.randomUUIDWithoutDash());

    // Cache those tokens, just for clearing 放入缓存中
    cacheStore.putAny(SecurityUtils.buildAccessTokenKey(user), token.getAccessToken(),
        ACCESS_TOKEN_EXPIRED_SECONDS, TimeUnit.SECONDS);
    cacheStore.putAny(SecurityUtils.buildRefreshTokenKey(user), token.getRefreshToken(),
        REFRESH_TOKEN_EXPIRED_DAYS, TimeUnit.DAYS);

    // Cache those tokens with user id
    cacheStore.putAny(SecurityUtils.buildTokenAccessKey(token.getAccessToken()), user.getId(),
        ACCESS_TOKEN_EXPIRED_SECONDS, TimeUnit.SECONDS);
    cacheStore.putAny(SecurityUtils.buildTokenRefreshKey(token.getRefreshToken()), user.getId(),
        REFRESH_TOKEN_EXPIRED_DAYS, TimeUnit.DAYS);

    return token;
}

cacheStore是手写的缓存类

private static final ConcurrentHashMap<String, CacheWrapper<String>> CACHE_CONTAINER =
    new ConcurrentHashMap<>();

用concurrentHashMap作为容器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值