目录
04、Spring Security从数据库中读取信息
pom依赖
application.properties
User
1.每个实体类的属性名都不一样,怎么知道你哪个字段表示用户名,那个字段表示密码,Spring Security提供了统一的方法实现UserDetails 接口
2.先重写方法,再实现get和set方法
3.重写了自动的,记得删掉get方法
UserService
当用户登录的时候,会自动调用到这个方法
UserMapper
UserMapper.xml
05、Spring Security自定义登录接口
LoginController
1.AuthenticationManager 就是 Spring Security 中的认证器,这是一个接口,这个接口只有一个实现类,ProviderManager,用户登录时侯具体的校验工作,就是由它来完成的。
2.new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());:拿到用户名和密码构建登录令牌
3.authenticationManager.authenticate(token);//这一步就是去执行登录
4.自定义登录接口要手动存信息进SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
5.登录失败抛出的异常
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
Security02ApplicationTests
测试BCryptPasswordEncoder加密:密码自带盐值
new BCryptPasswordEncoder(10);可以设置密码强度,加密起来慢,对于破解也慢了
SecurityConfig
06、Spring Security新的加密方法逐步替代原有的加密方法
内部源码:PasswordEncoderFactories
SecurityConfig
1.如果我们没有手动配置密码加密工具,那么默认PasswordEncoder,实际上是DelegatingPasswordEncoder
2.DelegatingPasswordEncoder 代理了所有密码加密器,他会根据密码的字符串格式,而选择一个合适的加密工具
3.例如数据库前缀{noop}
数据库可以多种加密方案共存
如何实现数据库统一类型密码加密-升级不同类型的密码
UserService
1.密码升级,实现UserDetailsPasswordService 接口
2.重新方法: *当用户登录的时候,会去自动检查当前用户密码是不是bcrypt,如果不是,则会自动进行密码升级,那么就会触发该方法
3.在这个方法种更新密码
UserService
UserMapper.xml
升级同等类型的密码
SecurityConfig
1.首先要有passwordEncoder 统一的密码加密类型
2.重写PasswordEncoderFactories加入@Bean改变密码强度
04、Spring Security从数据库中读取信息
pom依赖
org.springframework.boot
spring-boot-starter-security
org.mybatis.spring.boot
mybatis-spring-boot-starter 2.2.2
com.alibaba
druid
1.2.9
mysql
mysql-connector-java
runtime
src/main/java
**
@Override
public Collection extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
UserService
当用户登录的时候,会自动调用到这个方法
@Service
public class UserService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
}
UserMapper.xml
select * from user where username=#{username};
05、Spring Security自定义登录接口
LoginController
1.AuthenticationManager 就是 Spring Security 中的认证器,这是一个接口,这个接口只有一个实现类,ProviderManager,用户登录时侯具体的校验工作,就是由它来完成的。
2.new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());:拿到用户名和密码构建登录令牌
3.authenticationManager.authenticate(token);//这一步就是去执行登录
4.自定义登录接口要手动存信息进SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
5.登录失败抛出的异常
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login")
public Map login(@RequestBody User user) {
Map map = new HashMap<>();
//构建登录令牌
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
try {
//这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
authenticationManager.authenticate(token);
//将当前登录成功的用户信息存入到 SecurityContextHolder 中
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
map.put("status", "200");
map.put("message", "登录成功");
} catch (AuthenticationException exception) {
//登录失败
map.put("status", "500");
if (exception instanceof BadCredentialsException) {
map.put("message", "用户名或者密码写错,登录失败");
} else if (exception instanceof UsernameNotFoundException) {
//出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
} else if (exception instanceof AccountExpiredException) {
map.put("message", "账户过期,登录失败");
} else if (exception instanceof CredentialsExpiredException) {
map.put("message", "密码过期,登录失败");
} else if (exception instanceof DisabledException) {
map.put("message", "账户被禁用,登录失败");
} else if (exception instanceof LockedException) {
map.put("message", "账户被锁定,登录失败");
}
}
return map;
}
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
org.springframework.boot spring-boot-starter-securityorg.mybatis.spring.boot mybatis-spring-boot-starter2.2.2 com.alibaba druid1.2.9 mysql mysql-connector-javaruntime src/main/java ** @Override public Collection extends GrantedAuthority> getAuthorities() { return null; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } }
UserService
当用户登录的时候,会自动调用到这个方法
@Service
public class UserService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
}
UserMapper.xml
select * from user where username=#{username};
05、Spring Security自定义登录接口
LoginController
1.AuthenticationManager 就是 Spring Security 中的认证器,这是一个接口,这个接口只有一个实现类,ProviderManager,用户登录时侯具体的校验工作,就是由它来完成的。
2.new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());:拿到用户名和密码构建登录令牌
3.authenticationManager.authenticate(token);//这一步就是去执行登录
4.自定义登录接口要手动存信息进SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
5.登录失败抛出的异常
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login")
public Map login(@RequestBody User user) {
Map map = new HashMap<>();
//构建登录令牌
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
try {
//这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
authenticationManager.authenticate(token);
//将当前登录成功的用户信息存入到 SecurityContextHolder 中
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
map.put("status", "200");
map.put("message", "登录成功");
} catch (AuthenticationException exception) {
//登录失败
map.put("status", "500");
if (exception instanceof BadCredentialsException) {
map.put("message", "用户名或者密码写错,登录失败");
} else if (exception instanceof UsernameNotFoundException) {
//出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
} else if (exception instanceof AccountExpiredException) {
map.put("message", "账户过期,登录失败");
} else if (exception instanceof CredentialsExpiredException) {
map.put("message", "密码过期,登录失败");
} else if (exception instanceof DisabledException) {
map.put("message", "账户被禁用,登录失败");
} else if (exception instanceof LockedException) {
map.put("message", "账户被锁定,登录失败");
}
}
return map;
}
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
@Service
public class UserService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
}
UserMapper.xml
select * from user where username=#{username};
05、Spring Security自定义登录接口
LoginController
1.AuthenticationManager 就是 Spring Security 中的认证器,这是一个接口,这个接口只有一个实现类,ProviderManager,用户登录时侯具体的校验工作,就是由它来完成的。
2.new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());:拿到用户名和密码构建登录令牌
3.authenticationManager.authenticate(token);//这一步就是去执行登录
4.自定义登录接口要手动存信息进SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
5.登录失败抛出的异常
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login")
public Map login(@RequestBody User user) {
Map map = new HashMap<>();
//构建登录令牌
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
try {
//这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
authenticationManager.authenticate(token);
//将当前登录成功的用户信息存入到 SecurityContextHolder 中
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
map.put("status", "200");
map.put("message", "登录成功");
} catch (AuthenticationException exception) {
//登录失败
map.put("status", "500");
if (exception instanceof BadCredentialsException) {
map.put("message", "用户名或者密码写错,登录失败");
} else if (exception instanceof UsernameNotFoundException) {
//出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
} else if (exception instanceof AccountExpiredException) {
map.put("message", "账户过期,登录失败");
} else if (exception instanceof CredentialsExpiredException) {
map.put("message", "密码过期,登录失败");
} else if (exception instanceof DisabledException) {
map.put("message", "账户被禁用,登录失败");
} else if (exception instanceof LockedException) {
map.put("message", "账户被锁定,登录失败");
}
}
return map;
}
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
}
select * from user where username=#{username};
05、Spring Security自定义登录接口
LoginController
1.AuthenticationManager 就是 Spring Security 中的认证器,这是一个接口,这个接口只有一个实现类,ProviderManager,用户登录时侯具体的校验工作,就是由它来完成的。
2.new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());:拿到用户名和密码构建登录令牌
3.authenticationManager.authenticate(token);//这一步就是去执行登录
4.自定义登录接口要手动存信息进SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
5.登录失败抛出的异常
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login")
public Map login(@RequestBody User user) {
Map map = new HashMap<>();
//构建登录令牌
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
try {
//这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
authenticationManager.authenticate(token);
//将当前登录成功的用户信息存入到 SecurityContextHolder 中
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
map.put("status", "200");
map.put("message", "登录成功");
} catch (AuthenticationException exception) {
//登录失败
map.put("status", "500");
if (exception instanceof BadCredentialsException) {
map.put("message", "用户名或者密码写错,登录失败");
} else if (exception instanceof UsernameNotFoundException) {
//出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
} else if (exception instanceof AccountExpiredException) {
map.put("message", "账户过期,登录失败");
} else if (exception instanceof CredentialsExpiredException) {
map.put("message", "密码过期,登录失败");
} else if (exception instanceof DisabledException) {
map.put("message", "账户被禁用,登录失败");
} else if (exception instanceof LockedException) {
map.put("message", "账户被锁定,登录失败");
}
}
return map;
}
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
1.AuthenticationManager 就是 Spring Security 中的认证器,这是一个接口,这个接口只有一个实现类,ProviderManager,用户登录时侯具体的校验工作,就是由它来完成的。
2.new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());:拿到用户名和密码构建登录令牌
3.authenticationManager.authenticate(token);//这一步就是去执行登录
4.自定义登录接口要手动存信息进SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
5.登录失败抛出的异常
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login")
public Map login(@RequestBody User user) {
Map map = new HashMap<>();
//构建登录令牌
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
try {
//这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
authenticationManager.authenticate(token);
//将当前登录成功的用户信息存入到 SecurityContextHolder 中
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
map.put("status", "200");
map.put("message", "登录成功");
} catch (AuthenticationException exception) {
//登录失败
map.put("status", "500");
if (exception instanceof BadCredentialsException) {
map.put("message", "用户名或者密码写错,登录失败");
} else if (exception instanceof UsernameNotFoundException) {
//出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
} else if (exception instanceof AccountExpiredException) {
map.put("message", "账户过期,登录失败");
} else if (exception instanceof CredentialsExpiredException) {
map.put("message", "密码过期,登录失败");
} else if (exception instanceof DisabledException) {
map.put("message", "账户被禁用,登录失败");
} else if (exception instanceof LockedException) {
map.put("message", "账户被锁定,登录失败");
}
}
return map;
}
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
3.authenticationManager.authenticate(token);//这一步就是去执行登录
4.自定义登录接口要手动存信息进SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
5.登录失败抛出的异常
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login")
public Map login(@RequestBody User user) {
Map map = new HashMap<>();
//构建登录令牌
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
try {
//这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
authenticationManager.authenticate(token);
//将当前登录成功的用户信息存入到 SecurityContextHolder 中
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
map.put("status", "200");
map.put("message", "登录成功");
} catch (AuthenticationException exception) {
//登录失败
map.put("status", "500");
if (exception instanceof BadCredentialsException) {
map.put("message", "用户名或者密码写错,登录失败");
} else if (exception instanceof UsernameNotFoundException) {
//出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
} else if (exception instanceof AccountExpiredException) {
map.put("message", "账户过期,登录失败");
} else if (exception instanceof CredentialsExpiredException) {
map.put("message", "密码过期,登录失败");
} else if (exception instanceof DisabledException) {
map.put("message", "账户被禁用,登录失败");
} else if (exception instanceof LockedException) {
map.put("message", "账户被锁定,登录失败");
}
}
return map;
}
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
5.登录失败抛出的异常
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login")
public Map login(@RequestBody User user) {
Map map = new HashMap<>();
//构建登录令牌
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
try {
//这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
authenticationManager.authenticate(token);
//将当前登录成功的用户信息存入到 SecurityContextHolder 中
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
map.put("status", "200");
map.put("message", "登录成功");
} catch (AuthenticationException exception) {
//登录失败
map.put("status", "500");
if (exception instanceof BadCredentialsException) {
map.put("message", "用户名或者密码写错,登录失败");
} else if (exception instanceof UsernameNotFoundException) {
//出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
} else if (exception instanceof AccountExpiredException) {
map.put("message", "账户过期,登录失败");
} else if (exception instanceof CredentialsExpiredException) {
map.put("message", "密码过期,登录失败");
} else if (exception instanceof DisabledException) {
map.put("message", "账户被禁用,登录失败");
} else if (exception instanceof LockedException) {
map.put("message", "账户被锁定,登录失败");
}
}
return map;
}
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login")
public Map login(@RequestBody User user) {
Map map = new HashMap<>();
//构建登录令牌
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
try {
//这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
authenticationManager.authenticate(token);
//将当前登录成功的用户信息存入到 SecurityContextHolder 中
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
map.put("status", "200");
map.put("message", "登录成功");
} catch (AuthenticationException exception) {
//登录失败
map.put("status", "500");
if (exception instanceof BadCredentialsException) {
map.put("message", "用户名或者密码写错,登录失败");
} else if (exception instanceof UsernameNotFoundException) {
//出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
} else if (exception instanceof AccountExpiredException) {
map.put("message", "账户过期,登录失败");
} else if (exception instanceof CredentialsExpiredException) {
map.put("message", "密码过期,登录失败");
} else if (exception instanceof DisabledException) {
map.put("message", "账户被禁用,登录失败");
} else if (exception instanceof LockedException) {
map.put("message", "账户被锁定,登录失败");
}
}
return map;
}
SecurityConfig
1.注册LoginController的AuthenticationManager的认证器到spring中去
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security密码加密
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类
1.encode密码加密
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行
3.upgradeEncoding密码升级
4.自带盐值,相同的明文加密成密码不同
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
Security02ApplicationTests
测试BCryptPasswordEncoder加密:密码自带盐值
new BCryptPasswordEncoder(10);可以设置密码强度,加密起来慢,对于破解也慢了
@SpringBootTest
class Security02ApplicationTests {
@Test
void contextLoads() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
for (int i = 0; i < 10; i++) {
System.out.println(encoder.encode("123"));
}
}
}
$2a$10$NqbXkorf.Df13lefBvZspuD9wHj9CH3KUAYQCOBvqDRyze8XPVck6
$2a$10$kFIsIVV1y0Zuvs1cggzqnuZ7Qzgq0whzf3ozf0iGmbAxvBi731mji
$2a$10$giZViF92vIsZF6jrlERRB.lJm2XcMU8H/u3wox3QWCBDy9aLukcGK
$2a$10$UtWGZsdlBiLatF1CGGFC.uXibKwqydjS1Nb0ob5fGuVZyHi//NjwK
$2a$10$.TsjcfVJ0RYfAkREUM.RE.yfKrPrskRWflDjyxbo83QjkOKzsmU2C
$2a$10$lDppXh3Z32Q3qlpKdpXB8OP6UKKwRPlNqRV1CBtJ/BWl8XEuHh1a6
$2a$10$jpEDlzw36HGaSibKJpeu.uAn0YU9BhhjFrgoLAd8MGE1bkdr7zMW2
$2a$10$is5sKcAajPNQTTfojjjJvuSlY7s1VAe5kcyDoa7pWCGcmwETKglVi
$2a$10$eMoBXb3slmXSl/OM9Rjg2O1AYKZQdOtECZzh01YwmhDLxQbBrcwgi
$2a$10$wZP9XblkBXVwMdV4UiXyKubOcEW0zWgxOJVVGsz5p69l9.C2TU5t.
SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security新的加密方法逐步替代原有的加密方法
内部源码:PasswordEncoderFactories
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder());
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
//代理密码加密器
return new DelegatingPasswordEncoder(encodingId, encoders);
}
SecurityConfig
1.如果我们没有手动配置密码加密工具,那么默认PasswordEncoder,实际上是DelegatingPasswordEncoder
2.DelegatingPasswordEncoder 代理了所有密码加密器,他会根据密码的字符串格式,而选择一个合适的加密工具
3.例如数据库前缀{noop}
// @Bean
// PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
数据库可以多种加密方案共存
new BCryptPasswordEncoder(10);可以设置密码强度,加密起来慢,对于破解也慢了
@SpringBootTest
class Security02ApplicationTests {
@Test
void contextLoads() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
for (int i = 0; i < 10; i++) {
System.out.println(encoder.encode("123"));
}
}
}
$2a$10$NqbXkorf.Df13lefBvZspuD9wHj9CH3KUAYQCOBvqDRyze8XPVck6
$2a$10$kFIsIVV1y0Zuvs1cggzqnuZ7Qzgq0whzf3ozf0iGmbAxvBi731mji
$2a$10$giZViF92vIsZF6jrlERRB.lJm2XcMU8H/u3wox3QWCBDy9aLukcGK
$2a$10$UtWGZsdlBiLatF1CGGFC.uXibKwqydjS1Nb0ob5fGuVZyHi//NjwK
$2a$10$.TsjcfVJ0RYfAkREUM.RE.yfKrPrskRWflDjyxbo83QjkOKzsmU2C
$2a$10$lDppXh3Z32Q3qlpKdpXB8OP6UKKwRPlNqRV1CBtJ/BWl8XEuHh1a6
$2a$10$jpEDlzw36HGaSibKJpeu.uAn0YU9BhhjFrgoLAd8MGE1bkdr7zMW2
$2a$10$is5sKcAajPNQTTfojjjJvuSlY7s1VAe5kcyDoa7pWCGcmwETKglVi
$2a$10$eMoBXb3slmXSl/OM9Rjg2O1AYKZQdOtECZzh01YwmhDLxQbBrcwgi
$2a$10$wZP9XblkBXVwMdV4UiXyKubOcEW0zWgxOJVVGsz5p69l9.C2TU5t.
SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security新的加密方法逐步替代原有的加密方法
内部源码:PasswordEncoderFactories
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder());
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
//代理密码加密器
return new DelegatingPasswordEncoder(encodingId, encoders);
}
SecurityConfig
1.如果我们没有手动配置密码加密工具,那么默认PasswordEncoder,实际上是DelegatingPasswordEncoder
2.DelegatingPasswordEncoder 代理了所有密码加密器,他会根据密码的字符串格式,而选择一个合适的加密工具
3.例如数据库前缀{noop}
// @Bean
// PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
数据库可以多种加密方案共存
@SpringBootTest
class Security02ApplicationTests {
@Test
void contextLoads() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
for (int i = 0; i < 10; i++) {
System.out.println(encoder.encode("123"));
}
}
}
$2a$10$NqbXkorf.Df13lefBvZspuD9wHj9CH3KUAYQCOBvqDRyze8XPVck6
$2a$10$kFIsIVV1y0Zuvs1cggzqnuZ7Qzgq0whzf3ozf0iGmbAxvBi731mji
$2a$10$giZViF92vIsZF6jrlERRB.lJm2XcMU8H/u3wox3QWCBDy9aLukcGK
$2a$10$UtWGZsdlBiLatF1CGGFC.uXibKwqydjS1Nb0ob5fGuVZyHi//NjwK
$2a$10$.TsjcfVJ0RYfAkREUM.RE.yfKrPrskRWflDjyxbo83QjkOKzsmU2C
$2a$10$lDppXh3Z32Q3qlpKdpXB8OP6UKKwRPlNqRV1CBtJ/BWl8XEuHh1a6
$2a$10$jpEDlzw36HGaSibKJpeu.uAn0YU9BhhjFrgoLAd8MGE1bkdr7zMW2
$2a$10$is5sKcAajPNQTTfojjjJvuSlY7s1VAe5kcyDoa7pWCGcmwETKglVi
$2a$10$eMoBXb3slmXSl/OM9Rjg2O1AYKZQdOtECZzh01YwmhDLxQbBrcwgi
$2a$10$wZP9XblkBXVwMdV4UiXyKubOcEW0zWgxOJVVGsz5p69l9.C2TU5t.
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
//从 Spring Security 过滤器链中移除 CsrfFilter
.csrf().disable();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
06、Spring Security新的加密方法逐步替代原有的加密方法
内部源码:PasswordEncoderFactories
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder());
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
//代理密码加密器
return new DelegatingPasswordEncoder(encodingId, encoders);
}
SecurityConfig
1.如果我们没有手动配置密码加密工具,那么默认PasswordEncoder,实际上是DelegatingPasswordEncoder
2.DelegatingPasswordEncoder 代理了所有密码加密器,他会根据密码的字符串格式,而选择一个合适的加密工具
3.例如数据库前缀{noop}
// @Bean
// PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
数据库可以多种加密方案共存
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder());
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
//代理密码加密器
return new DelegatingPasswordEncoder(encodingId, encoders);
}
SecurityConfig
1.如果我们没有手动配置密码加密工具,那么默认PasswordEncoder,实际上是DelegatingPasswordEncoder
2.DelegatingPasswordEncoder 代理了所有密码加密器,他会根据密码的字符串格式,而选择一个合适的加密工具
3.例如数据库前缀{noop}
// @Bean
// PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
数据库可以多种加密方案共存
3.例如数据库前缀{noop}
// @Bean
// PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
数据库可以多种加密方案共存
// @Bean
// PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
如何实现数据库统一类型密码加密-升级不同类型的密码
UserService
1.密码升级,实现UserDetailsPasswordService 接口
2.重新方法: *当用户登录的时候,会去自动检查当前用户密码是不是bcrypt,如果不是,则会自动进行密码升级,那么就会触发该方法
3.在这个方法种更新密码
@Service
public class UserService implements UserDetailsService, UserDetailsPasswordService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
Integer i = userMapper.updatePassWordByUsernam(newPassword,user.getUsername());
if (i == 1){
User user1 = (User) user;
user1.setPassword(newPassword);
return user1;
}
return user;
}
UserService
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsernam(@Param("password") String newPassword, @Param("username")String username);
}
UserMapper.xml
update user set password = #{password} where username;
升级同等类型的密码
SecurityConfig
1.首先要有passwordEncoder 统一的密码加密类型
2.重写PasswordEncoderFactories加入@Bean改变密码强度
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder(20));
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
07、权限控制(核心功能)
1.HelloController:注明权限接口
- 设置可以访问的角色@PreAuthorize("hasRole('ROLE_user')")
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/user/hello")
@PreAuthorize("hasRole('ROLE_user')")
public String user() {
return "hello user";
}
@GetMapping("/admin/hello")
@PreAuthorize("hasRole('ROLE_admin')")
public String admin() {
return "hello admin";
}
2.SecurityConfig:设置权限
- .antMatchers("/admin
@Override
public Collection extends GrantedAuthority> getAuthorities() {
// SimpleGrantedAuthority是他唯一的实现类
List
list = new ArrayList<>();
return list;
// return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList());
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
5.UserService:在登录的成功的时候拿到用户角色
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
//如过查询到了用户,接下来就去查询用户的角色
user.setRoles(userMapper.getUserRolesByUid(user.getId()));
return user;
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsername(@Param("password") String newPassword, @Param("username")String username);
List getUserRolesByUid(Integer uid);
}
1.密码升级,实现UserDetailsPasswordService 接口
2.重新方法: *当用户登录的时候,会去自动检查当前用户密码是不是bcrypt,如果不是,则会自动进行密码升级,那么就会触发该方法
3.在这个方法种更新密码
@Service
public class UserService implements UserDetailsService, UserDetailsPasswordService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
Integer i = userMapper.updatePassWordByUsernam(newPassword,user.getUsername());
if (i == 1){
User user1 = (User) user;
user1.setPassword(newPassword);
return user1;
}
return user;
}
UserService
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsernam(@Param("password") String newPassword, @Param("username")String username);
}
UserMapper.xml
update user set password = #{password} where username;
升级同等类型的密码
SecurityConfig
1.首先要有passwordEncoder 统一的密码加密类型
2.重写PasswordEncoderFactories加入@Bean改变密码强度
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder(20));
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
07、权限控制(核心功能)
1.HelloController:注明权限接口
- 设置可以访问的角色@PreAuthorize("hasRole('ROLE_user')")
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/user/hello")
@PreAuthorize("hasRole('ROLE_user')")
public String user() {
return "hello user";
}
@GetMapping("/admin/hello")
@PreAuthorize("hasRole('ROLE_admin')")
public String admin() {
return "hello admin";
}
2.SecurityConfig:设置权限
- .antMatchers("/admin
@Override
public Collection extends GrantedAuthority> getAuthorities() {
// SimpleGrantedAuthority是他唯一的实现类
List
list = new ArrayList<>();
return list;
// return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList());
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
5.UserService:在登录的成功的时候拿到用户角色
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
//如过查询到了用户,接下来就去查询用户的角色
user.setRoles(userMapper.getUserRolesByUid(user.getId()));
return user;
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsername(@Param("password") String newPassword, @Param("username")String username);
List getUserRolesByUid(Integer uid);
}
3.在这个方法种更新密码
@Service
public class UserService implements UserDetailsService, UserDetailsPasswordService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
Integer i = userMapper.updatePassWordByUsernam(newPassword,user.getUsername());
if (i == 1){
User user1 = (User) user;
user1.setPassword(newPassword);
return user1;
}
return user;
}
UserService
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsernam(@Param("password") String newPassword, @Param("username")String username);
}
UserMapper.xml
update user set password = #{password} where username;
升级同等类型的密码
SecurityConfig
1.首先要有passwordEncoder 统一的密码加密类型
2.重写PasswordEncoderFactories加入@Bean改变密码强度
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder(20));
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
07、权限控制(核心功能)
1.HelloController:注明权限接口
- 设置可以访问的角色@PreAuthorize("hasRole('ROLE_user')")
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/user/hello")
@PreAuthorize("hasRole('ROLE_user')")
public String user() {
return "hello user";
}
@GetMapping("/admin/hello")
@PreAuthorize("hasRole('ROLE_admin')")
public String admin() {
return "hello admin";
}
2.SecurityConfig:设置权限
- .antMatchers("/admin
@Override
public Collection extends GrantedAuthority> getAuthorities() {
// SimpleGrantedAuthority是他唯一的实现类
List
list = new ArrayList<>();
return list;
// return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList());
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
5.UserService:在登录的成功的时候拿到用户角色
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
//如过查询到了用户,接下来就去查询用户的角色
user.setRoles(userMapper.getUserRolesByUid(user.getId()));
return user;
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsername(@Param("password") String newPassword, @Param("username")String username);
List getUserRolesByUid(Integer uid);
}
@Service
public class UserService implements UserDetailsService, UserDetailsPasswordService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
Integer i = userMapper.updatePassWordByUsernam(newPassword,user.getUsername());
if (i == 1){
User user1 = (User) user;
user1.setPassword(newPassword);
return user1;
}
return user;
}
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsernam(@Param("password") String newPassword, @Param("username")String username);
}
update user set password = #{password} where username;
升级同等类型的密码
SecurityConfig
1.首先要有passwordEncoder 统一的密码加密类型
2.重写PasswordEncoderFactories加入@Bean改变密码强度
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder(20));
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
07、权限控制(核心功能)
1.HelloController:注明权限接口
- 设置可以访问的角色@PreAuthorize("hasRole('ROLE_user')")
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/user/hello")
@PreAuthorize("hasRole('ROLE_user')")
public String user() {
return "hello user";
}
@GetMapping("/admin/hello")
@PreAuthorize("hasRole('ROLE_admin')")
public String admin() {
return "hello admin";
}
2.SecurityConfig:设置权限
- .antMatchers("/admin
@Override
public Collection extends GrantedAuthority> getAuthorities() {
// SimpleGrantedAuthority是他唯一的实现类
List
list = new ArrayList<>();
return list;
// return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList());
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
5.UserService:在登录的成功的时候拿到用户角色
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
//如过查询到了用户,接下来就去查询用户的角色
user.setRoles(userMapper.getUserRolesByUid(user.getId()));
return user;
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsername(@Param("password") String newPassword, @Param("username")String username);
List getUserRolesByUid(Integer uid);
}
2.重写PasswordEncoderFactories加入@Bean改变密码强度
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder(20));
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
07、权限控制(核心功能)
1.HelloController:注明权限接口
- 设置可以访问的角色@PreAuthorize("hasRole('ROLE_user')")
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/user/hello")
@PreAuthorize("hasRole('ROLE_user')")
public String user() {
return "hello user";
}
@GetMapping("/admin/hello")
@PreAuthorize("hasRole('ROLE_admin')")
public String admin() {
return "hello admin";
}
2.SecurityConfig:设置权限
- .antMatchers("/admin
@Override
public Collection extends GrantedAuthority> getAuthorities() {
// SimpleGrantedAuthority是他唯一的实现类
List
list = new ArrayList<>();
return list;
// return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList());
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
5.UserService:在登录的成功的时候拿到用户角色
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
//如过查询到了用户,接下来就去查询用户的角色
user.setRoles(userMapper.getUserRolesByUid(user.getId()));
return user;
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsername(@Param("password") String newPassword, @Param("username")String username);
List getUserRolesByUid(Integer uid);
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder(20));
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/user/hello")
@PreAuthorize("hasRole('ROLE_user')")
public String user() {
return "hello user";
}
@GetMapping("/admin/hello")
@PreAuthorize("hasRole('ROLE_admin')")
public String admin() {
return "hello admin";
}
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
//说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
throw new UsernameNotFoundException("用户不存在");
}
//如过查询到了用户,接下来就去查询用户的角色
user.setRoles(userMapper.getUserRolesByUid(user.getId()));
return user;
}
UserMapper
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
Integer updatePassWordByUsername(@Param("password") String newPassword, @Param("username")String username);
List getUserRolesByUid(Integer uid);
}



