上篇讲了如何简单实现security功能,但只能使用框架指定的账号密码,不符合我们的应用场景。这篇讲一下如何使用数据库账号密码实现登录流程
首先,还是创建我们的项目
然后是数据库的设计
然后是用户controller层的代码 UserController.java
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
UserService userService;
@RequestMapping("/list")
public List<User> list() {
List<User> list = userService.getList();
return list;
}
}
健康检查类controller层的代码 UserController.java
@RestController
@RequestMapping("ok")
public class OkController {
@RequestMapping("")
public String ok() {
System.out.println("security1 ok!");
return "security1 ok!";
}
}
security配置文件 WebSecurityConfig.java
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 需要放行的URL
*/
private static final String[] AUTH_WHITELIST = {
"/ok/**"
};
// 配置 URL 访问权限
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 开启 HttpSecurity 配置
.antMatchers(AUTH_WHITELIST).permitAll().anyRequest().authenticated() // 用户访问其它URL都必须认证后访问(登录后访问)
.and().formLogin() // 开启表单登录
.and().csrf().disable(); // 关闭csrf
}
}
来看一下我们的代码结构
通过user+控制台输出的密码,登录上系统之后,可以看到我们的用户列表信息
接下来,就是我们的主题了。
我们需要建一个MyUserDetailsService类,这个类主要用来往框架中注入账号、密码、角色、是否可用等信息,然后与登录接口传递过来的账号密码进行比对(注意,他会将前端传过来的密码进行加密,所以在我们注入的时候也需要加密,或者数据库直接存储密文)。代码如下。
package com.mu.security2.security;
import com.mu.security2.entity.User;
import com.mu.security2.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class MyUserDetailsService implements UserDetailsService {
@Autowired
UserService userService;
@Autowired
PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
System.out.println("进入》》》》MyUserDetailService");
System.out.println("登陆用户输入的用户名:" + s);
Map<String, Object> param = new HashMap<>();
param.put("username", s);
User user = userService.getUser(param);
if (user==null){
throw new UsernameNotFoundException("用户不存在");
}
String password = user.getPassword();
String encode = passwordEncoder.encode(password);
System.out.println("加密前的密码:"+ password);
System.out.println("加密后的密码:"+ encode);
UserVo userDetails = new UserVo();
userDetails.setUsername(user.getUsername());
userDetails.setPassword(user.getPassword());
userDetails.setAccountNonLocked(user.getLocked()==2);
userDetails.setEnabled(user.getDeleted()==2);
userDetails.setAccountNonExpired(true);
userDetails.setCredentialsNonExpired(true);
return userDetails;
}
}
对应securityUserDetails的用户类
package com.mu.security2.security;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Set;
public class UserVo implements UserDetails {
/**
* 账号
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 角色信息
*/
private Set<GrantedAuthority> authorities;
/**
* 账户是否未过期
*/
private boolean accountNonExpired;
/**
* 账户是否未锁定
*/
private boolean accountNonLocked;
/**
* 密码是否未过期
*/
private boolean credentialsNonExpired;
/**
* 账户是否可用
*/
private boolean enabled;
@Override
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public Set<GrantedAuthority> getAuthorities() {
return authorities;
}
public void setAuthorities(Set<GrantedAuthority> authorities) {
this.authorities = authorities;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
然后是在配置文件中配置我们自己创建的这个类,以及指定加密方式
package com.mu.security2.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.PasswordEncoder;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
MyUserDetailsService userDetailsService;
/**
* 需要放行的URL
*/
private static final String[] AUTH_WHITELIST = {
"/ok/**"
};
// 配置 URL 访问权限
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 开启 HttpSecurity 配置
.antMatchers(AUTH_WHITELIST).permitAll().anyRequest().authenticated() // 用户访问其它URL都必须认证后访问(登录后访问)
.and().formLogin() // 开启表单登录
.and().csrf().disable(); // 关闭csrf
}
// 配置用户及其对应的角色
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
//指定密码的加密方式
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
我们启动来试一下
控制台没有打印密码,用我们数据库的账号密码来尝试登录
页面显示了Bad credentials,密码错误,看一下控制台
原因呢是因为框架会将前端传过来的密码进行加密,然后再与我们注入的账号密码进行比对。因此我们复制控制台打印的加密后的密码到数据库中(建议数据库存储加密后的密码,防止密码泄露问题)。
成功用账号zx密码123登陆啦
源码地址
security: springboot security 整合,简单实现
附参考博客
基础介绍