这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战
整合springboot
前提
创建页面用于区分用户权限(A用户只能去add,不能去update)
1.创建新项目,导入web和thymeleaf
2.编写首页html,放在templates目录下!
3.编写add,update页面,放在templates/user目录下
4.编写controller跳转到首页,add,update
正式(模板)
1.导入shiro-spring整合包
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
2.编写配置类(基本框架),
先编写realm的类(需要自定义)
public class realm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("realm认证----------------------AuthorizationInfo");
return null;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throwsAuthenticationException {
System.out.println("realm授权----------------------AuthenticationInfo");
return null;
}
}
shiroConfig: 顺序是先realm,再manager,再ShiroFilterFactoryBean
@Configuration
public class shiroConfig {
// shiroFilterFactoryBan 这是第三部,需要manage管理
@Bean
public ShiroFilterFactoryBean bean(@Qualifier("manager") DefaultWebSecurityManagerdefaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
return bean;
}
// DefaultWebSecurityManager 这是第二部,因为manager需要realm
@Bean(name="manager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("realm") realmrealm){
DefaultWebSecurityManager defaultWebSecurityManager = newDefaultWebSecurityManager();
// 关联realm ,这里的参数不能直接realm(),因为realm是spring管理的,所以在方法的参数上用spring容器的bean对象
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}
// realm 对象,需要自定义(创建一个realm类) 这是第一步第一步
@Bean
public realm realm(){
return new realm();
}
}
3.具体实现用户权限
bean方法内
HashMap<String,String> map = new HashMap<>();
// 这里的资源写的是路径(controller里的),不是页面
map.put("/toadd","authc");
map.put("/toupdate","authc");
// 设置过滤器的内容(哪些路径要被过滤及其访问权限)
bean.setFilterChainDefinitionMap(map);
// 设置跳转登录页面,当被拦截时跳转到登录页面
bean.setLoginUrl("/tologin");
4.编写controller登录操作
@RequestMapping("/login")
public String login(String username,String password,Model model){
// 获取当前用户
Subject subject = SecurityUtils.getSubject();
// 封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try{
// 执行登录流程(所有验证的步骤shiro都帮我们做了),如果错误就会报异常
subject.login(token);
return "index";
}catch (UnknownAccountException e){
model.addAttribute("msg","用户不存在");
return "/user/login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "/user/login";
}
}
登录:
然后查看控制台:发现执行了realm的方法
两者之间我们并没有做什么联系,但是shiro就帮我们自动连接起来了,那么就可以在realm中添加登录数据
5.realm编写数据获取和认证
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throwsAuthenticationException {
System.out.println("realm认证----------------------AuthenticationInfo");
// 可以从数据库获取数据 ,这里手动设置数据
String username="YY";
String pasword = "1";
UsernamePasswordToken usertoken = (UsernamePasswordToken)token;
// 账号认证 ,认证参数里的token是全局存在的,登陆那边封装好了,这边就可以用
if(!usertoken.getUsername().equals(username)){
// return null 即抛出异常,由于是判断username的,异常就是用户名不存在
return null;
}
// 我们不做密码认证,有可能泄漏 。shiro暗地里做密码认证,
return new SimpleAuthenticationInfo("",pasword,"");
}
登录时会智能判断异常情况
6.设置未授权页面
// 设置未授权请求的页面
bean.setUnauthorizedUrl("/tounauthorized");
整合mybatis
前几部操作和springboot整合mybatis一样(可以多一步service层)
1.在realm的认证中添加数据库操作
// 从数据库获取数据
User user = userService.findUserByUsername(usertoken.getUsername());
// 账号认证 ,认证参数里的token是全局存在的,登陆那边封装好了,这边就可以用
if(user==null){
return null;
}
// 我们不做密码认证,有可能泄漏 。shiro暗地里做密码认证,
return new SimpleAuthenticationInfo("",user.getPassword(),"");
}
2.为当前用户添加权限
realme的授权方法(两种)
- 为所有用户授予该权限
- 通过认证中数据库操作获取user对象的权限并给予当前用户
注意:如果数据库没有区分大小写,那么输入大写也是会判定成功的 数据库字段从utf8_general_ci 改成 utf8_bin 可以了 或者增加一层判断 if(!user.getLoginname().equals(token.getUsername())){ throw new AuthenticationException(); }
// 授权,用于授权账号
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 只要经过这里就会授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 为每个用户授予该权限
// info.addStringPermission("user:add");
// 获取当前登录的用户
Subject subject = SecurityUtils.getSubject();
// 从下面的密码认证第一个 user拿到 user对象
User user = (User)subject.getPrincipal();
// 为subject设置数据库user对象里的权限
info.addStringPermission(user.getPerms());
return info;
}
用户登录情况:
map.put("/toadd","perms[user:add]");
map.put("/toupdate","perms[user:update]");
那么当YY登录时,只能访问update页面
当yzy登录时,不能访问任何网页
当y登录时,能访问add网页