-
准备
首先创建用户权限表
//用户表
CREATE TABLE `sys_user` (
`id` varchar(32) NOT NULL COMMENT 'id',
`username` varchar(64) DEFAULT NULL COMMENT '用户名',
`password` varchar(64) DEFAULT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
INSERT INTO `demo`.`sys_user` (`id`, `username`, `password`) VALUES ('1', 'admin', '123456');
//角色表
CREATE TABLE `sys_role` (
`id` varchar(32) NOT NULL COMMENT 'id',
`role_name` varchar(32) DEFAULT NULL COMMENT '角色名称',
`role_desc` varchar(32) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';
INSERT INTO `demo`.`sys_role` (`id`, `role_name`, `role_desc`) VALUES ('1', 'ROLE_ADMIN', '管理员');
//用户-角色表
CREATE TABLE `sys_user_role` (
`id` varchar(32) NOT NULL COMMENT 'id',
`user_id` varchar(32) DEFAULT NULL COMMENT '用户id',
`role_id` varchar(32) DEFAULT NULL COMMENT '角色id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色表';
INSERT INTO `demo`.`sys_user_role` (`id`, `user_id`, `role_id`) VALUES ('1', '1', '1');
然后用之前说的generator生成实体
-
集成
首先添加Shiro的依赖
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0</version>
</dependency>
然后创建自定义Realm
public class MyRealm extends AuthorizingRealm {
@Autowired
private SysUserMapper sysUserMapper;
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
//获得当前用户的用户名
String username = (String) authenticationToken.getPrincipal();
//从数据库中根据用户名查找用户
SysUser user = sysUserMapper.findByUserName(username);
if (user == null) {
log.info("没有用户名为{}的用户",username);
throw new UnknownAccountException("没有在本系统中找到对应的用户信息");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName());
return info;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//从凭证中获得用户名
String username = (String) SecurityUtils.getSubject().getPrincipal();
//根据用户名查询用户对象
SysUser user = sysUserMapper.findByUserName(username);
//查询用户拥有的角色
List<SysRole> roleList = user.getRoles();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
log.debug("用户{}拥有以下角色:");
for (SysRole role : roleList) {
//赋予用户角色
info.addStringPermission(role.getRoleName());
}
return info;
}
}
创建config类
@Configuration
public class ShiroConfiguration {
@Bean
public MyRealm realm(){
return new MyRealm();
}
//使用shiro-spring-boot-starter 1.4时,返回类型是SecurityManager会报错,直接引用shiro-spring则不报错
@Bean
public DefaultWebSecurityManager securityManager(MyRealm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
//拦截器.
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
//配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
// 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 :这是一个坑呢,一不小心代码就不好使了;
// authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/login.html", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
}
创建登录测试
@Controller
public class ShiroController {
@GetMapping("/login")
public String login(){
return "redirect:login.html";
}
@PostMapping("/login")
public String login(String username, String password){
Subject user = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
String returnUrl = "redirect:index.html";
String a = "1";
try {
//shiro帮我们匹配密码什么的,我们只需要把东西传给它,它会根据我们在UserRealm里认证方法设置的来验证
user.login(token);
} catch (UnknownAccountException e) {
//账号不存在
returnUrl = "redirect:login.html?error=0";
//账号不存在和下面密码错误一般都合并为一个账号或密码错误,这样可以增加暴力破解难度
} catch (DisabledAccountException e) {
//账号未启用
returnUrl = "redirect:login.html?error=1";
} catch (IncorrectCredentialsException e) {
//密码错误
returnUrl = "redirect:login.html?error=2";
} catch (Throwable e) {
//未知错误
returnUrl = "redirect:login.html?error=3";
} finally {
return returnUrl;
}
}
}
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title1</title>
</head>
<body>
<form method="post" action="/login">
用户名:<input name="username" /><br />
密码:<input name="password" /><br />
<input type="submit" value="登录" />
</form>
</body>
</html>
集成中的坑
1、config类中的securityManager()返回类型
如果jar包用spring-shiro,则返回SecurityManager即可,如果用shiro-spring-boot-starter 1.4,则需要返回DefaultWebSecurityManager,否则会报错
2、多环境配置
多环境配置中需要手动定义resuources目录下加载的文件,所以不要忘记将html加入进去
3、页面跳转问题
如果使用return "xx.html"方式的话,在登陆时,由于提交表单是post,而访问xx.html是get方法,所以会报错,需要使用redirect或者forward