自己第一次搞shiro的时候看了很多博客,做的时候还是一知半解的,也不能说别人的写的不好,可能自己领悟的比较慢,有些细节需要自己去思考,以至于花费的时间有点多,但也不都是坏处,这样有助于我们理解的更深刻。这篇文章希望可以帮助大家更快的完成spring集成shiro
工具
IntelliJ IDEA
关于怎么新建一个springboot项目我这里就不赘述了,不懂的小伙伴可以先看一下这篇博客idea从零新建springboot项目 。
第一步:
既然我们有了springboot项目,接下来第一步就是要引入shiro的依赖
Maven配置:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
关于怎么引入依赖以防万一我还是提一句为好,先贴出我的项目结构
引入依赖就是在pom.xml文件中加上上述maven配置的几行代码。pom.xml就是maven用来管理项目依赖的文件。
第二步:
springboot整合shiro只需要两个类,一个是ShiroConfig类,一个是CustomRealm类。当我们引入shiro所需的jar包后我们就可以开始第二步,那就是配置ShiroConfig类。
关于ShiroConfig类是什么:
没错这个类就是关于shiro的一些配置。包括过滤的文件和权限,密码加密的算法,其用注解等相关功能。
ShiroConfig类的配置:
package com.enlistentype.config;
import com.enlistentype.shiro.CustomRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.HashMap;
import java.util.Map;
/**
* @author Cyy
* @date 2020/2/14 12:22
*/
@Configuration
public class ShiroConfig {
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean (SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//设置登录,成功,权限不足跳转页面
shiroFilterFactoryBean.setLoginUrl("/ltLogin");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");
Map<String, String> map = new HashMap<>();
<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都可以匿名访问-->
map.put("/ltLogin/subLogin", "anon");
map.put("/**", "anon");
map.put("/admin/**", "authc");
map.put("/user/**", "authc");
//设置url,需要认证或者直接通过
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//将自定义验证方式加入容器
@Bean
public CustomRealm myShiroRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
}
//权限管理,配置Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(myShiroRealm());
return defaultWebSecurityManager;
}
}
一般就只需要这三个方法,方法也不复杂,注释也都写好了。
ShiroFilterFactoryBean方法:
就是shiro的过滤器,可以设置登录,权限不足跳转页面等。默认的过滤器还有:anno、authc、authcBasic、logout、noSessionCreation、perms、port、rest、roles、ssl、user过滤器。
具体的大家可以查看package org.apache.shiro.web.filter.mgt.DefaultFilter。这个类,常用的也就authc、anno。
securityManager方法:
这个方法主要是要设置项目的安全管理器,因为这里是一个web项目,所以我们使用的是DefaultWebSecurityManager,然后设置realm为自定义realm。这里还会有一个坑我们要注意,就是有时候会报错没有找到securityManager类,很有可能是系统自动导入的包是错误的,不是shiro的security包
CustomRealm方法:
将 customRealm的实例化,当然这里也可以利用注解的方式去注入。
第三步:
配置好ShiroConfig类后就是配置CustomRealm类了。
CustomRealm配置:
package com.enlistentype.shiro;
import com.enlistentype.common.Result;
import com.enlistentype.feignclient.FeignClientProxy;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* @author Cyy
* @date 2020/2/15 14:32
*/
@Component
public class CustomRealm extends AuthorizingRealm {
@Autowired
protected FeignClientProxy feignClientProxy;
//重写授权方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username = (String) principalCollection.getPrimaryPrincipal();
//使用远程方法获取主体的角色和权限
Result RoleNameOfUser = feignClientProxy.getRoleNamesOfUser(username);
Result PermissionOfUser = feignClientProxy.getPermissionString(username);
//打印获得的角色与权限
System.out.println(RoleNameOfUser.getData().get("roleSet"));
System.out.println(PermissionOfUser.getData().get("permissionSet"));
//将获得的角色与权限转换为set集合以便给setRole赋值
Set<String> role = new HashSet<String>((Collection<? extends String>) RoleNameOfUser.getData().get("roleSet"));
Set<String> permission = new HashSet<String>((Collection<? extends String>) PermissionOfUser.getData().get("permissionSet"));
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(role);
simpleAuthorizationInfo.setStringPermissions(permission);
return simpleAuthorizationInfo;
}
//重写认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取用户名
String username = (String) authenticationToken.getPrincipal();
//通过用户名获取密码
String password = getPasswordByUserName(username);
if (password == null) {
return null;
}
//构建认证信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, "customRealm");
return simpleAuthenticationInfo;
}
private String getPasswordByUserName(String username) {
return userMap.get(username);
}
//模拟数据库获取用户密码
Map<String, String> userMap = new HashMap<>();
{
userMap.put("James2", "123456");
super.setName("customRealm");
}
}
这个类也很简单,就是重载认证和授权的方法,首先都是通过subject获取用户名,我上面的map主要是模拟数据库获取用户信息,实际项目换成数据库查询操作即可。
最后一步:
到这里springboot整合shiro可以说是大功告成了,赶紧去写个controller测试一下吧。至于controller就是写一个登录逻辑,获取url的用户名和密码参数,封装成token,再subject.login(token)一下,可以在控制台打印是否认证成功。