今天小编给大家分享一下SpringBoot怎么整合Shiro的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
尼玛ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:028-86922220(备注:SSL证书合作)期待与您的合作!
我们将我们的SpringBoot应用整合shiro,主要目的就是让shiro帮我们处理认证和授权的相关内容。也就是说,我们需要让shiro接管我们SpringBoot应用的会话。让用户的每一次请求都经过shiro进行认证和授权。因此,我们需要将用户请求拦截下来转发给shiro处理,这个拦截器是shiro提供的,ShiroFilter
。
步骤:
用户通过客户端(浏览器、手机App、小程序)发起请求
ShiroFilter拦截请求并判断请求访问的资源是否为受保护资源:
2.1 是,则执行步骤3
2.2 不是,则直接放行
判断用户是否已通过认证:
3.1 是 ,则执行步骤4
3.2 否,将用户请求重定向到认证页面,让用户先认证
获取用户权限信息和访问资源所需要的权限信息进行比对:
4.1 用户具备访问权限,则放行
4.2 用户不具备权限,返回403的相应提示
我们通过MySQL保存我们的认证和权限的相关数据。采用用户-角色-权限模型实现动态管理用户权限信息。
我们将系统当中的菜单、按钮、后端接口都抽象成系统的资源数据。以下是数据库表的设计:
文末提供sql脚本的下载。
创建一个SpringBoot的web应用,并引入如下依赖
org.apache.shiro shiro-spring-boot-web-starter 1.6.0
这里代码就省略了,不影响理解,完整代码可以从文末提供的方式中下载。
/**自定义Realm,使用mysql数据源 * @author 赖柄沣 bingfengdev@aliyun.com * @version 1.0 * @date 2020/10/6 9:09 */ public class MySQLRealm extends AuthorizingRealm { @Autowired private IUserService userService; @Autowired private IRoleService roleService; @Autowired private IResourceService resourceService; /** * 授权 * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); ListroleList = roleService.findByUsername(username); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); for (Role role : roleList) { authorizationInfo.addRole(role.getRoleName()); } List roleIdList = new ArrayList<>(); for (Role role : roleList) { roleIdList.add(role.getRoleId()); } List resourceList = resourceService.findByRoleIds(roleIdList); for (Resource resource : resourceList) { authorizationInfo.addStringPermission(resource.getResourcePermissionTag()); } return authorizationInfo; } /** * 认证 * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { if(token==null){ return null; } String principal = (String) token.getPrincipal(); User user = userService.findByUsername(principal); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName()); return simpleAuthenticationInfo; } }
shiro中的Realm对象充当了认证、授权数信息的据源作用。关于更多自定义Realm的内容请参考我的另一篇文章《Shiro入门学习—使用自定义Realm完成认证|练气中期》 。
/**shiro配置类 * @author 赖柄沣 bingfengdev@aliyun.com * @version 1.0 * @date 2020/10/6 9:11 */ @Configuration public class ShiroConfig { /** * 创建ShiroFilter拦截器 * @return ShiroFilterFactoryBean */ @Bean(name = "shiroFilterFactoryBean") public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); //配置不拦截路径和拦截路径,顺序不能反 HashMapmap = new HashMap<>(5); map.put("/authc/**","anon"); map.put("/login.html","anon"); map.put("/js/**","anon"); map.put("/css/**","anon"); map.put("/**","authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); //覆盖默认的登录url shiroFilterFactoryBean.setLoginUrl("/authc/unauthc"); return shiroFilterFactoryBean; } @Bean public Realm getRealm(){ //设置凭证匹配器,修改为hash凭证匹配器 HashedCredentialsMatcher myCredentialsMatcher = new HashedCredentialsMatcher(); //设置算法 myCredentialsMatcher.setHashAlgorithmName("md5"); //散列次数 myCredentialsMatcher.setHashIterations(512); MySQLRealm realm = new MySQLRealm(); realm.setCredentialsMatcher(myCredentialsMatcher); return realm; } /** * 创建shiro web应用下的安全管理器 * @return DefaultWebSecurityManager */ @Bean public DefaultWebSecurityManager getSecurityManager(Realm realm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm); SecurityUtils.setSecurityManager(securityManager); return securityManager; } }
在编写shiro配置类这一步,需要大家注意的是,因为我们使用的是md5+salt+hash加密我们的密码,因此要换掉默认的凭证匹配器CredentialsMatcher对象,对于这部分的内容请参考我的另一篇文章《shiro入门学习–使用MD5和salt进行加密|练气后期》 。
/**认证请求参数 * @author 赖柄沣 bingfengdev@aliyun.com * @version 1.0 * @date 2020/10/7 15:12 */ @Data public class LoginVO implements Serializable { private String username; private String password; }
/**认证模块 * @author 赖柄沣 bingfengdev@aliyun.com * @version 1.0 * @date 2020/10/6 10:07 */ @RestController @RequestMapping("/authc") public class AuthcController { @Autowired private AuthcService authcService; @PostMapping("/login") public boolean login(@RequestBody LoginVO loginVO){ return authcService.login(loginVO); } @GetMapping("/unauthc") public String unauthc(){ return "请先登录"; } }
/** * @author 赖柄沣 bingfengdev@aliyun.com * @version 1.0 * @date 2020/10/7 15:15 */ @Service public class AuthcServiceImpl implements AuthcService { @Override public boolean login(LoginVO loginVO) throws AuthenticationException { if (loginVO==null){ return false; } if (loginVO.getUsername()==null||"".equals(loginVO.getUsername())){ return false; } if (loginVO.getPassword() == null || "".equals(loginVO.getPassword())){ return false; } Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(loginVO.getUsername(), loginVO.getPassword()); subject.login(token); return true; } }
/**产品模块 * @author 赖柄沣 bingfengdev@aliyun.com * @version 1.0 * @date 2020/10/6 10:14 */ @RestController @RequestMapping("/product") public class ProductController { @RequiresPermissions("product:get") @GetMapping("/get/list") public String getProductList() { return "productList"; } @RequiresPermissions("product:delete") @GetMapping("/delete") public String deleteProduct() { return "删除产品数据"; } }
对于注解实现访问控制,shiro主要有两个注解:RequiresPermissions和RequiresRoles。均可以用在类和方法上。具体用在哪可以根据自己的系统权限划分粒度决定。
对于这两个注解,有两个参数:
value
:分别对应permission的权限字符串值和role的角色名称;
logical
:逻辑运算符。这是一个枚举类型,有AND
和OR
两个值。当使用AND
时表示需要满足所有传入的value
值,OR
表示仅需满足一个value
即可。默认为AND
关于shiro权限(访问控制)的更多内容,可以阅读我的另一篇文章《shiro入门学习–授权(Authorization)|筑基初期》
默认的消息提示可以换一下。
以上就是“SpringBoot怎么整合Shiro”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注创新互联行业资讯频道。