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进行验证;这样存储的密码,就需要是先通过该类加密过字符串。
通过如上代码,即实现了真实用户的登陆验证;