公司工作需要使用自建的云平台,虽然我是嵌入式工程师但是因为人手不足(主要还是建站的人走了,没人会Java)所以交由我来维护。
这次有了新需求,需要进行权限的分类和管理,由于原先的代码已经经了好几手了(心累啊!!),我需要保持原先的结构不动的情况下加入这些功能,那么原先的方式已经不满足需求了。
查阅了资料以后,决定直接使用UserDetailsService的形式对原先页面进行改造。
我们原先的spring-security.xml有如下代码:
<authentication-manager erase-credentials="false">
<authentication-provider>
<jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="select username,password,1 as enabled from sys_user where username=?"
authorities-by-username-query="select u.username, r.name as role from sys_user u,sys_role_user ur, sys_role r where u.id=ur.Sys_User_id and r.id = ur.Sys_Role_id and u.username= ? "
/>
authentication-provider>
authentication-manager>
这里的authentication-provider是使用了直接使用jdbc对数据库进行读取,但是在商业项目中我们不能将数据库结构直接暴露,所以我们要采用UserDetailsService的形式对于用户数据进行管理,同时也方便后期对于权限等地方的操作。
我们这里使用自定义的UserDetailsService来代替原先对数据库的直接操作:
<authentication-manager erase-credentials="false">
<authentication-provider user-service-ref="myUserDetailsService">
authentication-provider>
authentication-manager>
然后我们在后端,对myUserDetailsService这个类需要进行具体的设计,但是在此之前,我们需要自定义好UserDetails。
package com.hzmsc.scada.entity;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class User implements UserDetails{
/**
* @title: User
* @author: zza
* @date: 2020/3/9 17:05
* @description: User用于权限验证和获取个人信息等方面,要注意和Users类的区别
*/
private int id;
private String username;
private String password;
private boolean enabled;
private Collection<? extends GrantedAuthority> authorities;
public User(int id, String username, String password, boolean enabled) {
super();
this.id = id;
this.username = username;
this.password = password;
this.enabled = enabled;
}
public User(int id, String username, String password, boolean enabled,
Collection<? extends GrantedAuthority> authorities) {
super();
this.id = id;
this.username = username;
this.password = password;
this.enabled = enabled;
this.authorities = authorities;
}
public int getId(){
return this.id;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@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;
}
@Override
public String toString() {
return "MyUserDetails [id=" + id + ", username=" + username
+ ", password=" + password + ", enabled=" + enabled
+ ", authorities=" + authorities + "]";
}
}
定义好User类以后我们就可以开始设计myUserDetailsService了。
package com.hzmsc.scada.service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import com.hzmsc.scada.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.core.GrantedAuthority;
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 javax.sql.DataSource;
public class MyUserDetailsService implements UserDetailsService {
@Autowired
public void setDatasource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
JdbcTemplate jdbcTemplate;
private final String sqlLoadUser;
private final String sqlLoadAuthorities;
private final RowMapper<User> myUserDetailsRowMapper;
private final RowMapper<GrantedAuthority> authorityRowMapper;
private static Logger logger = LoggerFactory
.getLogger(MyUserDetailsService.class);
public MyUserDetailsService(){
super();
sqlLoadUser ="select id,username,password,enabled from sys_user where username=?";
sqlLoadAuthorities = "select r.name as role from sys_user u,sys_role_user ur, sys_role r where u.id=ur.Sys_User_id and r.id = ur.Sys_Role_id and u.username= ? ";
myUserDetailsRowMapper = new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
return (new User(rs.getInt(1),
rs.getString(2),
rs.getString(3),
rs.getBoolean(4)));
}
};
System.out.println();
authorityRowMapper = new RowMapper<GrantedAuthority>() {
@Override
public GrantedAuthority mapRow(ResultSet rs, int rowNum)
throws SQLException {
return new SimpleGrantedAuthority(rs.getString(1));
}
};
}
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
try {
System.out.println("++++++++");
User userFromQuery = jdbcTemplate.queryForObject(sqlLoadUser,
myUserDetailsRowMapper,username);
logger.debug("查询得到用户:{}", userFromQuery);
List<GrantedAuthority> authorities = jdbcTemplate.query(
sqlLoadAuthorities, authorityRowMapper, username);
logger.debug("得到其权限:{}", authorities);
return new User(userFromQuery.getId(), userFromQuery.getUsername(),
userFromQuery.getPassword(), userFromQuery.isEnabled(),
authorities);
} catch (EmptyResultDataAccessException e) {
logger.debug("查询结果集为空:{}", username);
throw new UsernameNotFoundException("用户名或密码不正确");
}
}
}
注意开始的时候需要添加动态数据源,否则装配的时候会发生故障(-_-||这里被坑死)。