002-SpringBoot Security 安全验证——开发使用——替换用户

续上一篇《SpringBoot Security 安全验证——源码查看》本篇当中主要记录如何使用;

首先,解决用户来源的问题。之前说,用户是使用默认提供的user用户。我们把它替换成自己从库中读取的方式。

那么如何替换呢?

很简单,就是继承自接口UserDetailsService写一个实现类,就可以了。

 

可以暂时不用写实现逻辑,只定义好这样一个类,就可以通过断点调试来验证了。注意一定要给类添加@Service注解。目的是使其成为一个Bean。

这时,会有疑惑,为什么声明了就会自动调入了呢?下面的这段源码很关键。所以后面的加密处理都源自同样的原理。

 

 补充好前面的逻辑,因为是Demo,就直接写内存数据来代替数据库操作

 

 

package org.tzl.domain.dto;

import lombok.*;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.tzl.domain.po.User;

import java.util.Collection;

/*******************************************************
 * 安全验证用户实现类 
 *
 * @author: tzl
 * @time: 2022-05-01 17:56:26
 * *****************************************************/
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class UserDetailsDTO implements UserDetails {

    private User user;

    // 有哪些认证权限
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    // 密码
    @Override
    public String getPassword() {
        return user.getPassword();
    }

    // 用户名
    @Override
    public String getUsername() {
        return user.getUsername();
    }

    // 是否账户未过期
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    // 是否账户未被锁定
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    // 是否证书未过期
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    // 是否已启用
    @Override
    public boolean isEnabled() {
        return true;
    }
}
package org.tzl.domain.po;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/*******************************************************
 * 用户实体 
 *
 * @author: tzl
 * @time: 2022-05-01 11:23:16
 * *****************************************************/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    Long userId;
    String username;
    String password;
}
package org.tzl.dao;

import org.springframework.security.core.userdetails.UserDetails;

/*******************************************************
 * 用户数据提供接口 
 *
 * @author: tzl
 * @time: 2022-05-01 11:27:27
 * *****************************************************/
public interface UserDao {
    UserDetails loadUserByUsername(String username);
}
package org.tzl.dao.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Repository;
import org.tzl.dao.UserDao;
import org.tzl.data.Data;
import org.tzl.domain.dto.UserDetailsDTO;
import org.tzl.domain.po.User;

import javax.annotation.Resource;

/*******************************************************
 * 用户数据提供实现类 
 *
 * @author: tzl
 * @time: 2022-05-01 11:27:56
 * *****************************************************/
@Repository("userDaoLocalImpl")
public class UserDaoLocalImpl implements UserDao {

    @Resource
    private Data<User> data;

    @Override
    public UserDetails loadUserByUsername(String username) {
        User user = data.getData().stream().filter(u -> u.getUsername().equals(username)).findFirst().get();
        return new UserDetailsDTO(user);
    }
}
package org.tzl.data;

import java.util.List;

/*******************************************************
 * 数据存储接口 
 *
 * @author: tzl
 * @time: 2022-05-01 11:30:10
 * *****************************************************/
public interface Data<T> {
    List<T> getData();
}
package org.tzl.data.impl;

import org.springframework.stereotype.Component;
import org.tzl.data.Data;
import org.tzl.domain.po.User;

import java.util.ArrayList;
import java.util.List;

/*******************************************************
 * 用户数据存储类,用来模拟数据库数据 
 *
 * @author: tzl
 * @time: 2022-05-01 11:29:15
 * *****************************************************/
@Component
public class UserDataImpl implements Data {
    @Override
    public List<User> getData() {
        List<User> users = new ArrayList<>();
        users.add(new User(1L, "tzl", "tzl"));
        return users;
    }
}
package org.tzl.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;

/*******************************************************
 * 安全验证配置 
 *
 * @author: tzl
 * @time: 2022-05-01 11:08:41
 * *****************************************************/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                return rawPassword.toString();
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return rawPassword.toString().equals(encodedPassword);
            }
        };
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
    }
}

SecurityConfig中的PasswordEncoder是为了密码匹配时使用的,示例中,只是原文进行验证,推荐使用BCryptPasswordEncoder进行验证;这样存储的密码,就需要是先通过该类加密过字符串。

通过如上代码,即实现了真实用户的登陆验证;

 

posted on 2022-05-01 19:28  走调的钢琴  阅读(185)  评论(0)    收藏  举报