之前我们完成了Spring+Shiro的最基本配置搭建,现在我们再增加上DB,毕竟没有哪个系统会将用户、角色、权限等信息硬编码到代码里。DB选用myslq。
数据库准备
脚本如下。依然是两个用户:admin和guest。admin拥有角色admin以及权限permission1、permission2;guest拥有角色guest以及权限permission1、permission2。
create table test.shiro_user ( id int auto_increment primary key, username varchar(50), password varchar(50) ); create table test.shiro_role ( id int auto_increment primary key, role varchar(50) ); create table test.shiro_permission ( id int auto_increment primary key, permission varchar(50) ); create table test.shiro_user_r_role ( userid int, roleid int ); create table test.shiro_user_r_permission ( userid int, permissionid int ); insert into test.shiro_user(id, username, password) values (1, 'admin', 'admin'); insert into test.shiro_user(id, username, password) values (2, 'guest', 'guest'); insert into test.shiro_role(id, role) values (1, 'admin'); insert into test.shiro_role(id, role) values (2, 'guest'); insert into test.shiro_permission(id, permission) values (1, 'permission1'); insert into test.shiro_permission(id, permission) values (2, 'permission2'); insert into test.shiro_permission(id, permission) values (3, 'permission3'); insert into test.shiro_permission(id, permission) values (4, 'permission4'); insert into test.shiro_user_r_role(userid, roleid) values (1, 1); insert into test.shiro_user_r_role(userid, roleid) values (2, 2); insert into test.shiro_user_r_permission(userid, permissionid) values (1, 1); insert into test.shiro_user_r_permission(userid, permissionid) values (1, 2); insert into test.shiro_user_r_permission(userid, permissionid) values (2, 3); insert into test.shiro_user_r_permission(userid, permissionid) values (2, 4);
pom依赖
再之前的基础上又增加了spring-jdbc和mysql的数据库驱动,因为要连接数据库嘛
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
application.properties
增加连接数据库的相关配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://192.168.2.12:3306/test?characterEncoding=utf8 spring.datasource.username=root spring.datasource.password=onceas
Dao和Service
dao和service就没什么好说的了,Controller不用动
@Repository public class LoginDao { private final JdbcTemplate jdbcTemplate; @Autowired public LoginDao(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public List<User> getUserByUsername(String username) { String sql = "select id, username, password from shiro_user where username=?"; return jdbcTemplate.query(sql, new Object[]{username}, new BeanPropertyRowMapper<User>(User.class)); } public List<String> getRoleByUsername(String username) { String sql = "select role from shiro_role A " + "join shiro_user_r_role B on A.id = B.roleid " + "join shiro_user C on B.userid = C.id " + "where C.username=?"; return jdbcTemplate.queryForList(sql, new Object[]{username}, String.class); } public List<String> getPermissionByUsername(String username) { String sql = "select permission from shiro_permission A " + "join shiro_user_r_permission B on A.id = B.permissionid " + "join shiro_user C on B.userid = C.id " + "where C.username=?"; return jdbcTemplate.queryForList(sql, new Object[]{username}, String.class); } }
@Service public class LoginService { private final LoginDao loginDao; @Autowired public LoginService(LoginDao loginDao) { this.loginDao = loginDao; } public List<User> getUserByUsername(String username) { return loginDao.getUserByUsername(username); } public List<String> getRoleByUsername(String username) { return loginDao.getRoleByUsername(username); } public List<String> getPermissionByUsername(String username) { return loginDao.getPermissionByUsername(username); } }
修改Realm
调整Realm,用户验证和授权改为从数据库中获取数据
public class PropertiesRealm extends AuthorizingRealm { private final LoginService loginService; @Autowired public PropertiesRealm(LoginService loginService) { this.loginService = loginService; } // 用户认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { if (authenticationToken instanceof UsernamePasswordToken) { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); String password = new String(token.getPassword()); List<User> users = loginService.getUserByUsername(username); if (users == null || users.size() != 1) { throw new AuthenticationException("用户名或密码错误"); } User user = users.get(0); if (!user.getPassword().equals(password)) { throw new AuthenticationException("用户名或密码错误"); } return new SimpleAuthenticationInfo(username, password, getName()); } else if (authenticationToken instanceof RememberMeAuthenticationToken) { RememberMeAuthenticationToken token = (RememberMeAuthenticationToken) authenticationToken; // TODO: 2018/10/24 return null; } else if (authenticationToken instanceof HostAuthenticationToken) { HostAuthenticationToken token = (HostAuthenticationToken) authenticationToken; // TODO: 2018/10/24 return null; } else { throw new AuthenticationException("未知的AuthenticationToken类型"); } } // 用户授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { String username = (String) principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.addRoles(loginService.getRoleByUsername(username)); simpleAuthorizationInfo.addStringPermissions(loginService.getPermissionByUsername(username)); return simpleAuthorizationInfo; } }
调整SpringApplication
因为修改后的realm需要LoginService的支持,所以相应的调整SpringApplication,其他地方不变。
@Bean public PropertiesRealm propertiesRealm(LoginService loginService) { return new PropertiesRealm(loginService); }