接着上一篇https://blog.csdn.net/qq_23967965/article/details/96484858继续,上一篇使用系统默认用户与生成密码安全认证登录访问以及通过手动配置一个默认账户访问。现在我们通过自定义配置UserDetailsService接口来实现登录访问。
1.创建新的实体类SysUser.java
SysUser.java
import java.io.Serializable;
import java.util.List;
public class SysUser implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private String password;
private List<SysRole> roles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<SysRole> getRoles() {
return roles;
}
public void setRoles(List<SysRole> roles) {
this.roles = roles;
}
}
2.创建UserPrincipal.java实体
UserPrincipal.java
import java.util.Collection;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class UserPrincipal implements UserDetails{
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private String password;
// private int status;
private Set<GrantedAuthority> authorities;
public UserPrincipal(Integer id, String userName, String password) {
this.id = id;
this.username = userName;
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
return this.authorities;
}
public void setAuthorities(Set<GrantedAuthority> authorities) {
this.authorities = authorities;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
/**
* 指定账户是否被锁定,锁定账户无法验证
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 账户是否过期,过期无法验证
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 指示是否已过期的用户的凭据(即密码),过期的凭据防止认证
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 是否被禁用,禁用的账户不能身份验证
*/
@Override
public boolean isEnabled() {
return true;
}
}
注:上面的部分字段暂时用不到,用到的主要有用户名和密码两个字段。其他字段留作以后使用。
3.创建UserPasswordEncoder.java
UserPasswordEncoder.java
import org.springframework.security.crypto.password.PasswordEncoder;
public class UserPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encodedPassword.equals(rawPassword.toString());
}
}
4.创建UserPrincipalService.java
UserPrincipalService.java
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import cn.zoulang.frame.modules.sys.model.SysUser;
@Component
//@Service
public class UserPrincipalService implements UserDetailsService {
/**
* 返回一个UserDetails,其实现类是UserPrincipal
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserPrincipal userPrincipal = null;
try {
// 从数据库查询获取sysUser信息
SysUser sysUser = new SysUser();
sysUser.setUsername("admin");
sysUser.setPassword("123456");
userPrincipal = new UserPrincipal(sysUser.getId(), sysUser.getUsername(), sysUser.getPassword() );
}catch(Exception e) {
System.out.println("权限配置时获取系统用户出错");
}
return userPrincipal;
}
}
5.修改WebSecurityConfig.java
WebSecurityConfig.java
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
UserPrincipalService userPrincipalService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userPrincipalService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new UserPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//设置登录,注销,表单登录不用拦截,其他请求要拦截
http.authorizeRequests().antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.logout().permitAll()
.and()
.formLogin();
}
@Override
public void configure(WebSecurity web) throws Exception {
//设置静态资源不要拦截
web.ignoring().antMatchers("/js/**","/cs/**","/images/**");
}
}
上述代码全部创建完成后,我们就可以启动项目,然后在浏览器输入http://localhost:8899/user/query,在弹出的登录框里面输入账号admin,密码123456即可登录。
6.修改为从数据库查询
6.1新建数据库表
如上图,建立sys_user,sys_role,sys_user_role,sys_permission,sys_permission_role表,这些表是做用户角色权限控制的,但是这篇文章我们只用到了sys_user这张表,其他表会在以后用到。
注:这里下面实际上主要用到sys_user这个实体,其他在model包中的实体将在以后使用。不过这里还是一起贴出代码。
6.2创建相关类
SysUser.java
import java.io.Serializable;
import java.util.List;
public class SysUser implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private String password;
private List<SysRole> roles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<SysRole> getRoles() {
return roles;
}
public void setRoles(List<SysRole> roles) {
this.roles = roles;
}
}
SysRole.java
import java.io.Serializable;
public class SysRole implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name; // 角色名称
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
SysPermission.java
import java.io.Serializable;
public class SysPermission implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name; // 权限名称
private String description; // 权限描述
private String url; // 授权连接
private Integer pid; // 父节点ID
private String method; // 请求方式
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
}
SysUserMapper.java
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import cn.zoulang.frame.modules.sys.model.SysUser;
@Mapper
public interface SysUserMapper {
SysUser findUserByName(@Param("userName")String userName);
List<SysUser> findAll();
}
SysUserService.java
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.zoulang.frame.modules.sys.mapper.SysUserMapper;
import cn.zoulang.frame.modules.sys.model.SysUser;
@Service
public class SysUserService {
@Autowired
SysUserMapper sysUserMapper;
public SysUser findUserByName(String userName) {
return sysUserMapper.findUserByName(userName);
}
public List<SysUser> findAll() {
return sysUserMapper.findAll();
}
}
SysUserController.java
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.zoulang.frame.modules.sys.model.SysUser;
import cn.zoulang.frame.modules.sys.service.SysUserService;
//@Controller
@RestController
@RequestMapping("/user")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
@RequestMapping("/query")
public List<SysUser> findUserByName() {
return sysUserService.findAll();
}
}
配置SysUserMapper.xml文件
SysUserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.zoulang.frame.modules.sys.mapper.SysUserMapper">
<resultMap id="SysUser" type="cn.zoulang.frame.modules.sys.model.SysUser">
<result column="ID" property="id"/>
<result column="USERNAME" property="username"/>
<result column="PASSWORD" property="password"/>
</resultMap>
<select id="findUserByName" parameterType="String" resultMap="SysUser">
SELECT * FROM sys_user WHERE username = #{userName}
</select>
<select id="findAll" resultMap="SysUser">
SELECT * FROM sys_user
</select>
</mapper>
7.修改application.properties配置数据库
注意这个地方的数据库名称,之前我们使用的是名为test的数据库,现在我们修改为frame数据库,因为这里的表字段等有发生变化。
8.修改UserPrincipalService.java类
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import cn.zoulang.frame.modules.sys.model.SysUser;
import cn.zoulang.frame.modules.sys.service.SysUserService;
//@Component
@Service
public class UserPrincipalService implements UserDetailsService {
@Autowired
private SysUserService sysUserService;
/**
* 返回一个UserDetails,其实现类是UserPrincipal
*/
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
// 从数据库查询获取sysUser信息
SysUser sysUser = sysUserService.findUserByName(userName);
if(null == sysUser) {
System.out.println("该用户名不存在!");
}
// try {
// sysUser.setUsername("admin");
// sysUser.setPassword("123456");
// userPrincipal = new UserPrincipal(sysUser.getId(), sysUser.getUsername(), sysUser.getPassword() );
// }catch(Exception e) {
// System.out.println("权限配置时获取系统用户出错");
// }
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
return new org.springframework.security.core.userdetails.User(sysUser.getUsername(),
sysUser.getPassword(), authorities);
}
}
可以看到,这里我们修改了从数据库获取用户数据。
特别注意:这里由于在sys包中的很多名称都和之前在test包里面的类名称重名,需要删除原来test包及其配置的sql配置文件(src/main/resources下的test下的SysUserMapper.xml文件),否则会报错。或者不想删除,可以将注入的类起个其他名称,我这里直接删除原来test包里面相关文件。
9.测试
添加数据
首先在数据库中向sys_user添加两条数据,包括用户名和密码及ID,比如我这里添加了用户名:admin 密码:admin ,以及用户名: user 密码:user ,ID分别设置为1和2.
开启项目测试
运行项目,浏览器输入地址:http://localhost:8899/user/query,在登录框中输入我们数据库有的用户名和密码即可登录。如admin/admin或user/user.