Spring Security 用户密码配置
配置文件
Spring Boot中整合Spring Security只需添加一个依赖即可,非常方便,启动项目时:控制台会输出一个密码,在浏览器访问时会弹出一个登录框,默认用户为user,而密码就是控制台输出的那段字符串。
那这样就会有一个问题,每次访问都需要复制控制台的密码,当然,这个是可以配置的,可以在配置文件当中进行如下配置。
spring.security.user.name=user
spring.security.user.password=youyuan
此时,访问浏览器登录即可。
内存配置
当然也可以基于内存进行配置,创建一个类继承自WebSecurityConfigurerAdapter然后实现其configuration方法即可。
@Configuration
public class MultiHttpSecurityConfig extend WebSecurityConfigurerAdapter{
//对密码不进行加密处理
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Autowired
/*用户认证*/
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("youyuan").password("1011").roles("admin")
.and()
.withUser("zs").password("1011").roles("user");
}
}
注意:基于内存的用户配置在配置角色时不需要添加"ROLE_ "前缀
数据库配置
当然在实际开发情况下,用户与密码还是要从数据库当中加载,基于数据库进行认证。
首先我们准备三个表,分别为用户,角色,还有用户角色表。用户角色表关联每个用户所对应的角色。
在配置基本的数据库信息:
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.password=root
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/testcharacterEncoding=utf-8&serverTimezone=UTC
然后在创建对应的实体类:
@Data
public class User implements UserDetails {
private Integer id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
private List<Role> roles;
@Override
/*返回用户所有角色*/
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : this.roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));
}
return authorities;
}
@Override
/*账户是否没有过期*/
public boolean isAccountNonExpired() {
return true;
}
@Override
/*账户是否未锁定*/
public boolean isAccountNonLocked() {
return !locked;
}
@Override
/*密码是否未过期*/
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
}
在UserService类中实现UserDetailsService接口
@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) {
throw new UsernameNotFoundException("用户不存在!");
}
/**
*查询出相应的角色
*添加角色到user中**/
user.setRoles(userMapper.getUserRolesById(user.getId()));
return user;
}
}
最后在Spring Security进行配置:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Override
/**
*用户认证
**/
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
**表单配置详解
**/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()//开启登录配置
.anyRequest().authenticated() //表示访问接口,需要进行认证
.and()
.formLogin()
.loginProcessingUrl("/doLogin")
.loginPage("/login") //默认的登录页面
.usernameParameter("user")//定义登录时,用户名的 key,默认为 username
.passwordParameter("pwd") //定义登录时,用户密码的 key,默认为 password
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("status",200);
map.put("msg",authentication.getPrincipal());
//浏览器返回json数据
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("status",401);
if (e instanceof LockedException){
map.put("msg","账户被锁定,登录失败");
}else if (e instanceof BadCredentialsException){
map.put("msg","用户名或密码输入错误,登录失败");
}else if (e instanceof DisabledException){
map.put("msg","账户被禁用,登录失败");
}else if(e instanceof AccountExpiredException){
map.put("msg","账户过期,登录失败");
}else if (e instanceof CredentialsExpiredException){
map.put("msg","密码过期,登录失败");
}else {
map.put("msg","登录失败");
}
//浏览器返回json数据
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.permitAll() //和表单登录相关的接口统统都直接通过
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("status",200);
map.put("msg","注销登录成功");
//浏览器返回json数据
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.permitAll()
.and()
.csrf().disable();
}
}