springboot集成shiro
一:maven导入jar包
<!-- shiro与Spring的集成包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
二:创建一个自定义的Realm
在config中创建一个shiro的包,用于存放shiro相关的类,在里面创建一个名为MyRealm的类,内容如下:
package com.quyi.hello.config.shiro;
import com.quyi.hello.entity.User;
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 java.util.HashSet;
import java.util.Set;
/***
* 这里使用假数据 真数据可以在这里导入Mapper对象从数据库中查询
*/
public class MyRealm extends AuthorizingRealm {
/***
* 权限--授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
String username = (String)principalCollection.getPrimaryPrincipal();
//根据用户名查询角色 存入authorizationInfo
Set<String> roles = new HashSet<>();
roles.add("admin");
roles.add("teacher");
authorizationInfo.setRoles(roles);
//根据用户名查询权限 存入authorizationInfo
Set<String> per = new HashSet<>();
roles.add("score:add");
roles.add("score:delete");
authorizationInfo.setStringPermissions(per);
return authorizationInfo;
}
/***
* 登录--认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户输入的用户名
String uname = token.getPrincipal().toString();
//创建假数据 模拟从数据库中取出来的信息
User user = new User();
user.setUsername("admin");
user.setPassword("123");
if(uname == null || "".equals(uname)){
throw new AccountException("请输入用户名和密码");
}
//因为是模拟 所以这里表示数据库中查不到这个用户名 表示用户不存在
if(!uname.equals(user.getUsername())){
throw new UnknownAccountException("用户不存在");
}
//第一个参数传用户名或者user对象 第二个参数为数据库中取出来的密码 第三个为当前realm的名字
return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
}
}
在正式开发中,按照逻辑将假数据替换成数据库中查询即可
三:创建shiro的配置类
package com.quyi.hello.config.shiro;
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.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
import org.springframework.context.annotation.DependsOn;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/***
* shiro过滤工厂
* @param securityManager
* @return
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
//并不是每次调用接口就会执行,而是调用需要操作码(permission)的接口就会执行
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");//设置跳转的登录页面
shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");//没有权限跳转的页面
shiroFilterFactoryBean.setSuccessUrl("/index");
Map<String, String> map = new LinkedHashMap<>();
map.put("/login2", "anon");//登录接口放行
//必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证
map.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
/***
* 注入安全管理器
* @return
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
defaultSecurityManager.setRealm(myRealm());//把我们自定义的realm放进去
return defaultSecurityManager;
}
/***
* 注入我们自定义的realm
* @return
*/
@Bean
public MyRealm myRealm() {
return new MyRealm();
}
/**
* Shiro生命周期处理器
*
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
* @return
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
}
四:登陆接口
@PostMapping("/login2")
public String login2(@RequestBody User user){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
try {
subject.login(token);
}catch (UnknownAccountException e){
e.printStackTrace();
System.out.println("未知账户/没找到帐号");
return "未知账户/没找到帐号";
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误");
return "密码错误";
}catch (Exception e){
e.printStackTrace();
System.out.println("其他异常");
return "其他异常" + e.getMessage();
}
return "登录成功";
}
五:shiro四种权限控制方式
-
代码级别权限控制
public String edit(){ Subject subject = SecurityUtils.getSubject(); subject.checkPermission("staff-edit"); Staff staff = staffService.findById(model.getId()); staff.setName(model.getName()); staff.setTelephone(model.getTelephone()); staff.setHaspda(model.getHaspda()); staff.setStandard(model.getStandard()); staff.setStation(model.getStation()); staffService.update(staff); return LIST; }
配置好了权限控制后,就可以开始测试了。
六:shiro过滤工厂-参数讲解:
securityManager:这个属性是必须的。
loginUrl :没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。
successUrl :登录成功默认跳转页面,不配置则跳转至”/”。如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。不跳转到此。
unauthorizedUrl :没有权限默认跳转的页面
七:shiro过滤器描述
anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString
是你访问的url里的?后面的参数。
authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
八:shiro异常类
认证异常类
异常类 | 描述 |
---|---|
org.apache.shiro.authc.pam.UnsupportedTokenException | 身份令牌异常,不支持的身份令牌 |
org.apache.shiro.authc.UnknownAccountException | 未知账户/没找到帐号,登录失败 |
org.apache.shiro.authc.LockedAccountException | 帐号锁定 |
org.apache.shiro.authc.DisabledAccountException | 用户禁用 |
org.apache.shiro.authc.ExcessiveAttemptsException | 登录重试次数,超限。只允许在一段时间内允许有一定数量的认证尝试 |
org.apache.shiro.authc.ConcurrentAccessException | 一个用户多次登录异常:不允许多次登录,只能登录一次 。即不允许多处登录 |
org.apache.shiro.authc.AccountException | 账户异常 |
org.apache.shiro.authc.ExpiredCredentialsException | 过期的凭据异常 |
org.apache.shiro.authc.IncorrectCredentialsException | 错误的凭据异常 |
org.apache.shiro.authc.CredentialsException org.apache.shiro.authc.AuthenticationException | 凭据异常 |
权限异常类
异常类 | 描述 |
---|---|
org.apache.shiro.authz.HostUnauthorizedException org.apache.shiro.authz.UnauthorizedException | 没有访问权限,访问异常 |
org.apache.shiro.authz.UnauthenticatedException org.apache.shiro.authz.AuthorizationException | 授权异常 |
org.apache.shiro.ShiroException | shiro全局异常 |
orizedException
org.apache.shiro.authz.UnauthorizedException | 没有访问权限,访问异常 |
| org.apache.shiro.authz.UnauthenticatedException
org.apache.shiro.authz.AuthorizationException | 授权异常 |
| org.apache.shiro.ShiroException | shiro全局异常 |