Shiro三个核心:
Subject:用户主体(把操作交给SecurityManager)
SecurityManager:安全管理器(关联Realm)
Realm:Shiro连接数据的桥梁
1.引入shiro相关maven依赖
<!-- shiro与spring整合依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- thymeleaf对shiro的标签扩展 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2. 创建Realm身份验证器
创建类后 继承 AuthorizingRealm,重写doGetAuthorizationInfo(授权逻辑)和doGetAuthenticationInfo(认证逻辑)方法。
package cn.czl.shiro;
import cn.czl.domain.User;
import cn.czl.domain.UserPower;
import cn.czl.service.PowerService;
import cn.czl.service.UserService;
import cn.czl.service.impl.PowerServiceImpl;
import cn.czl.service.impl.UserServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* 自定义Realm
* @author RedRush
* */
public class UserRealm extends AuthorizingRealm {
//注入业务
@Autowired
private UserService userService = new UserServiceImpl();
@Autowired
private PowerService powerService = new PowerServiceImpl();
/**
* 执行授权逻辑
* */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
//对资源进行授权
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//获取当前用户的id
Subject subject = SecurityUtils.getSubject();
User user = (User)subject.getPrincipal();
//到数据库查询当前用户的授权字符串
User dbUser = userService.findBasicById(user.getUid());
//添加资源的授权字符串(关联授权过滤器后面的字符串)
// authorizationInfo.addStringPermission("user:add");
// authorizationInfo.addStringPermission(dbUser.getPerms());
//添加角色的授权字符串
authorizationInfo.addRole(dbUser.getRole());
//将权限列表批量导入
List <UserPower> userPowers= powerService.getUpower(dbUser.getPid());
for (UserPower userPower:userPowers){
System.out.println(userPower);
authorizationInfo.addStringPermission(userPower.getPerm());
}
// List<Perm> perms = permDao.getPermById(user.getUid());
// for (Perm perm : perms){
// authorizationInfo.addStringPermission(perm.getPermName());
// }
return authorizationInfo;
}
/**
* 执行认证逻辑
* */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//编写shiro判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
System.out.println(token.getUsername());
User user = userService.findByName(token.getUsername());
if(user == null){
//用户名不存在
return null;//shiro底层会抛出UnknownAccountException
}
//2.判断密码("返回给login方法的数据(授权方法可获取)","数据库密码","realm名字")
return new SimpleAuthenticationInfo(user, user.getUpwd(), "");
}
}
3. 创建ShiroConfig(Shiro配置)
package cn.czl.shiro;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* shiro的配置类
* @author RedRush
* */
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
* 创建shiro过滤器工厂
* */
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//1.设置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//2.添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截
* 常用的过滤器:
* anon:无需认证(登陆)即可访问
* authc:必须认证才可以访问
* user:如果使用rememeberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* roles:该资源必须得到角色权限才可以访问
* */
Map<String, String> filterMap = new LinkedHashMap<String, String>();
//设置白名单(无需认证访问页面)
filterMap.put("/testThymeleaf", "anon");
//放行login请求
filterMap.put("/login", "anon");
//授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权页面
filterMap.put("/manage", "roles[manage]");
filterMap.put("/add", "perms[user:add]");
filterMap.put("/update", "perms[user:update]");
//设置拦截url
filterMap.put("/*", "authc");
// filterMap.put("/add", "authc");
// filterMap.put("/update", "authc");
//修改调整的登陆页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
* 创建默认网络安全管理员
* */
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 创建Realm
* 身份验证器Realm(开发者自行编写设置认证、授权业务)
* */
@Bean(name = "userRealm")
public UserRealm gerRealm(){
return new UserRealm();
}
/**
* 配置ShiroDialect,用于thymeleaf和shiro标签配合使用
* shiro方言(shiro权限判断标签)
* */
@Bean
public ShiroDialect getShiroDialect(){
System.out.println("创建ShiroDialect");
return new ShiroDialect();
}
}
4. Controller层使用shiro进行认证
@RequestMapping("/login")
public String login(String name, String password, Model model){
System.out.println("name" + name + ";password" + password);
/**
* 使用shiro编写认证操作
* */
//1.获取Subject
Subject subject = SecurityUtils.getSubject();
//2.获取用户数据
UsernamePasswordToken token = new UsernamePasswordToken(name, password);
//3.执行登陆方法
try {
subject.login(token);
//登陆成功
//执行"/testThymeleaf"请求,重定向,跳转到test.html
return "redirect:/testThymeleaf";
}catch (UnknownAccountException e){
//e.printStackTrace();
//登陆失败:用户名不存在
model.addAttribute("msg", "用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){
//登陆失败:密码错误
model.addAttribute("msg","密码错误");
return "login";
}
}
5. 页面中使用Thymeleaf配合shiro进行模块权限控制
<div shiro:hasPermission="user:update">
<a href="update">用户更新</a>
</div>
<div shiro:hasRole="manager">管理员您好</div>
项目目录结构:
我的github源码,数据库表结构和数据也放进去了,欢迎学习交流。
有用的话,给个小星星吧。阿里嘎多https://github.com/Iron-Rush/springboot-shiro.git