用户名+密码
系统默认登录用户名:user
密码每次服务启动后随机生成密码
用户信息获取原理(数据库获取)
实现该接口,security默认自动生成密码关闭。框架源码:
package org.springframework.security.core.userdetails; public interface UserDetailsService { UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException; }
获取用户信息逻辑,封装在security的UserDetailsService接口,实现该接口只有一个方法UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
该方法接收用户登陆时的username,根据username可以从数据库,redis,LDAP等读取用户信息,用户信息封装到UserDetails接口的实现类中,实现类User;
框架源码
public class User implements UserDetails, CredentialsContainer { private static final long serialVersionUID = 530L; private static final Log logger = LogFactory.getLog(User.class); private String password; private final String username; private final Set<GrantedAuthority> authorities; private final boolean accountNonExpired; private final boolean accountNonLocked; private final boolean credentialsNonExpired; private final boolean enabled;
User.UserBuilder设置用户名,密码,权限信息返回UserDetails; loadUserByUsername返回UserDetails,security接收并以此来验证访问是否有效.
密码加密解密
框架源码
自定义密码验证(密码加密验证器)
public interface PasswordEncoder { String encode(CharSequence rawPassword);//用来加密;原始密码加密后的值,前端传过来的明文密码 boolean matches(CharSequence rawPassword, String encodedPassword);//加密后的密码与用户上传的密码(明文)是否匹配 default boolean upgradeEncoding(String encodedPassword) { return false; } }
org.springframework.security.crypto.bcrypt;包实现
可自定义实现该接口
实际场景中,用户密码是加密后传输,保存的密码都是加密的
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.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //http.formLogin() //表单登陆认证方法,浏览器跳转到specurity默认登陆页面 http.httpBasic()//浏览器弹出登陆对话框登陆认证方式 .and() .authorizeRequests() ////设置请求符合访问资源的权限 .anyRequest().authenticated(); //对任何请求都要登陆认证后才能访问 } @Bean public PasswordEncoder passwordEncoder() { //return NoOpPasswordEncoder.getInstance(); //已弃用 return new BCryptPasswordEncoder(); } }
处理用户校验
用户密码校验
@Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private PasswordEncoder pw; @Resource private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { //TODO 查询用户信息(mysql,redis,ldap) User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getName, s)); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } String pwd = pw.encode(user.getPasswd()); //TODO 从数据库获取用户相关权限 String[] authorities = {"admin", "test"};//在configure方法中设置验证权限 UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(user.getName()).password(pwd).authorities(authorities).build(); return userDetails; } }
设置用户帐户过期校验
实现UserDetailsService接口的User类的boolean isAccountNonExpired()方法。
根据数据库表中设计来设定用户过期时间。
如果当前时间大于过期时间,说明用户已过期,设置User.UserBuilder.accountExpired(true),默认为false
@Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private PasswordEncoder pw; @Resource private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { //TODO 查询用户信息(mysql,redis,ldap) User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getName, s)); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } String pwd = pw.encode(user.getPasswd()); //TODO 从数据库获取用户相关权限 String[] authorities = {"admin", "test"}; //在configure方法中设置验证权限 org.springframework.security.core.userdetails.User.UserBuilder builder = org.springframework.security.core.userdetails.User.withUsername(user.getName()).password(pwd).authorities(authorities); //查询用户的信息中created表示为过期时间,判断created是否小于当前时间 Long currentTime = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); Long expireTime = user.getCreated().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); if (currentTime>expireTime){ builder.accountExpired(true); } //UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(user.getName()).password(pwd).authorities(authorities).build(); UserDetails userDetails = builder.build(); return userDetails; }
设置用户密码过期校验
与设置用户帐户过期校验逻辑一样,默认为false
User.UserBuilder.credentialsExpired(true);
设置用户锁定校验
与设置用户帐户过期校验逻辑一样,默认为false
User.UserBuilder accountLocked(true)
设置用户是否可用校验
User.UserBuilder disabled(true)
校验总结
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
User类对这四个方法的实现只是返回false或true,判断逻辑是自己判断出结果,通过调置User的属性值是false或true,在由这几个方法返回;
自己可实现UserDetails接口,将逻辑判断直接写入这几个方法中。
登陆成功,客户端将JSESSIONID保存在Cookie里,每次请求携带
"Cookie": "JSESSIONID=1C6C3BD094405290E5802CB98F627E19"
标签:SpringSecurity,String,用户,springframework,认证,private,User,security,表单 From: https://www.cnblogs.com/wangzhilei-src/p/17967576