首先是新建一个springboot项目,把依赖装好
然后把mybatis整合进项目中,这里便不多赘述
装好后便可以开始整合这个安全框架了
首先在配置之前,我们需要明确shrio的三大对象
- Subject 用户
- SecurityManager 管理所有用户
- Realm 连接数据
这三个对象贯穿整个项目的整合
1.导包
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency>
2.编写配置类
@Configuration
public class ShiroConfig {
//ShrioFilterFactoryBean
//DefaultWebSecurityManager
//创建realm对象,需要自定义类
}
我们分别把通过这三个类将shrio的核心三个对象声明出来,再对其中他们的属性进行一个设置就行
2.1创建realm对象
public class SelfRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
return null;
}
}
这个类继承 AuthorizingRealm
每次进行登录时都会首先运行这个realm对象
2.2创建shrio三个核心对象
我们需要在shrio配置类中进行建立
@Configuration
public class ShiroConfig {
//ShiroFilterFactoryBean
public ShiroFilterFactoryBean getShrioFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager)
{
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
return shiroFilterFactoryBean;
}
//DefaultWebSecurityManager
@Bean(name = "SecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("myrealm") MyRealm myrealm)
{
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(myrealm);
return defaultWebSecurityManager;
}
//创建realm对象,需要自定义类
@Bean(name = "myrealm")
public MyRealm getMyRealm()
{
return new MyRealm();
}
}
配置过程中是从最后的一个realm对象创建起,这样逻辑才能顺畅些。至此shrio的基本框架就搭建完成了,接下来是对权限以及认证的一个操作。
3.操作权限与认证
3.1 登录拦截
在getShrioFilterFactoryBean方法中实现拦截功能
加入以下代码
//添加shrio内置过滤器 /* * anon:无需认证便可访问 * authc:必须认证才能访问 * user:必须拥有记住我才能使用 * perms:拥有对某个资源才能访问 * role:拥有某个角色 * */ Map linkedMap = new LinkedHashMap<String,Object>(); linkedMap.put("/add","authc"); linkedMap.put("/","anon"); shiroFilterFactoryBean.setFilterChainDefinitionMap(linkedMap); shiroFilterFactoryBean.setLoginUrl("/login");
便可实现登录的拦截
3.2用户认证
首先需要在controller层接收用户传递的账号与密码
@RequestMapping("/login")
public String login(String username, String password, Model model)
{
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装用户的登录信息
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
try {
subject.login(usernamePasswordToken);
return "index";
} catch (UnknownAccountException e) {
model.addAttribute("msg","用户名错误");
e.printStackTrace();
return "login";
}catch (IncorrectCredentialsException e)
{
model.addAttribute("msg","密码错误");
return "login";
}
Token可以说是一个 令牌,可以全局使用,将username与password放于令牌中,在后面的操作中可在myrealm中的认证方法中通过他直接获取username和password。
myrealm编写认证方法
@Override
//认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = userService.getUserByUsername(token.getUsername());
// 我这块就写了一个异常
if (user == null) {
throw new UnknownAccountException();
}
// 实际上有好些异常可以往外抛
// IncorrectCredentialsException 凭证错误 可以理解为密码错误
// DisabledAccountException 账号被禁用
// LockedAccountException 账号被锁定
// ExcessiveAttemptsException 登录失败次数超过限制
// ... 还有好些 他们都是 AuthenticationException的子类
// 这里返回一个认证信息
return new SimpleAuthenticationInfo(user.getUsername(), user.getPwd(), getName());
}
根据username查出数据库中对应的数据,封装于user中,值得注意的是,这个方法是直接把密码的判断封装起来,我们是看不到判断的过程的,我们只需返回AuthenticationInfo的实现类,根据代码填入相应的参数。至此认证便完成了
3.3用户权限
首先我们可以在shrioconfig通过map设置哪些页面需要权限控制
Map linkedMap = new LinkedHashMap<String,Object>(); linkedMap.put("/add","authc"); linkedMap.put("/update","authc"); linkedMap.put("/add","roles[vip1]"); linkedMap.put("/update","roles[vip1]"); linkedMap.put("/","anon"); shiroFilterFactoryBean.setFilterChainDefinitionMap(linkedMap); shiroFilterFactoryBean.setLoginUrl("/tologin");
已这个为例子,至于为什么权限要这么些(roles[vip1]),这是官方的文档中ini文件中的写法,这里提醒一下。
其次我们便可以在自定义的realm中的权限方法中编写想要的逻辑
@Override
// 这块是权限鉴定 就是登录成功后把权限查出来,授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 首先要把用户查出来
User user = userService.getUserByUsername(principalCollection.toString());
// 然后把他的角色和权限查出来 扔进
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole(user.getRole());
return info;
}
至此简单的权限认证便实现完了,主要还是要知道,subject,scurityManager、realm这三个核心对象,subject往往被使用在realm中进行获取对象。