springboot 版本为2.1.6
org.apache.shiro
shiro-spring
1.4.0
com.github.theborakompanioni
thymeleaf-extras-shiro
2.0.0
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.mgt.DefaultSecurityManager;
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.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig
{
/*
* 1.创建ShiroFilterFactoryBean,核心配置的一部分
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultSecurityManager securityManager)
{
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 1.anon:无需认证(登录)可以访问
// 2.authc:必须认证才可以访问
// 3.user:如果使用remember me 的功能可以直接访问
// 4.perms:该资源必须得到资源权限才可以访问
// 5.role:该资源必须得到角色权限才可以访问
Map<String, String> filterMapper = new LinkedHashMap<>();
/**
* 放行静态资源
*/
filterMapper.put("/css/**","anon");
filterMapper.put("/fonts/**","anon");
filterMapper.put("/images/**","anon");
filterMapper.put("/js/**","anon");
/**
* 放行公共界面
*/
filterMapper.put("/reporttable","anon");
filterMapper.put("/index","anon");
filterMapper.put("/login","anon");
filterMapper.put("/","anon");
filterMapper.put("/reportsearch","anon");
filterMapper.put("/unauth","anon");
//这个要放在最后,拦截所有资源,如果放在放行资源前面,放行资源会不生效
filterMapper.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMapper);
shiroFilterFactoryBean.setLoginUrl("/tologin");
//如果开启了注解,这个无权限界面是无法进入的,下面会配置一个类专门拦截无权限
shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
return shiroFilterFactoryBean;
}
/*
* 2.创建DefalutWebSecurityManager
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm)
{
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//需要关联一个Realm
defaultWebSecurityManager.setRealm(userRealm);
return defaultWebSecurityManager;
}
/*
* 3.创建Realm,Realm类是自定义的一个类,用来做用户认证以及权限管理
*/
@Bean(name = "userRealm")
public UserRealm getUseRealm()
{
return new UserRealm();
}
/**
* 创建shiro跟themeleaf交互的ShiroDialect
* @return
*/
@Bean
public ShiroDialect getShiroDialect()
{
return new ShiroDialect();
}
@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(@Qualifier("securityManager")DefaultSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
/**
* 自定义Realm类,继承于shiro定义的一个类
*/
import com.ht.intergrity.domian.UserLogin;
import com.ht.intergrity.service.UserLoginService;
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.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class UserRealm extends AuthorizingRealm
{
/**
* 执行核心授权逻辑
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
{
System.out.println("执行授权逻辑");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
/*UserLogin是自定义的一个用户类,用来做用户登录,存放了用户名跟密码,通过下面的方法可以获取当前登录的用户信息,
**用户来源是由认证逻辑中的return new SimpleAuthenticationInfo(loginuser,loginuser.getPassword(),getName());
*这段代码存放的
*/
UserLogin userLogin = (UserLogin) SecurityUtils.getSubject().getPrincipal();
//调用了service层中的方法,通过用户id获取用户的权限,将授权关键字并存放到set列表中,最后放入授权
List<Map<String, String>> permByUserid = userLoginService.findPermByUserid(userLogin.getId());
Set<String> stringSet = new HashSet<>();
for(Map<String,String> map:permByUserid)
{
String permsvalue = map.get("permsvalue");
stringSet.add(permsvalue);
}
info.setStringPermissions(stringSet);
return info;
}
@Autowired
private UserLoginService userLoginService;
/**
* 执行认证逻辑
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException
{
System.out.println("正在执行认证逻辑");
/**
*token是由用户登录的control层中存放的,可以由此获取到用户名跟密码
*/
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
UserLogin loginuser = userLoginService.findByUsername(token.getUsername());
if(loginuser==null)
{
//返回null表示用户不存在
return null;
}
//2.判断密码
return new SimpleAuthenticationInfo(loginuser,loginuser.getPassword(),getName());
}
}
/**
*所有登录由此进入
*/
@RequestMapping(value = "/tologin",method = RequestMethod.GET)
public String tologin()
{
return "login";
}
/**
*通过登录界面发送过来的post请求来进行shiro认证
*/
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String toLogin(String username, String password, Model model)
{
/**
* 使用shiro编写认证
*/
//1,获取subject
Subject subject = SecurityUtils.getSubject();
//2,封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//3,执行登录方法
try
{
subject.login(token);
//登录成功
//登录成功,重定向到表单页面
return "redirect:reportcheck";
}
catch (UnknownAccountException e)
{
//登录失败,用户名不存在
model.addAttribute("subinfo", "用户名不存在!");
return "login";
}
catch (IncorrectCredentialsException e)
{
//登录失败,密码错误
model.addAttribute("subinfo", "密码错误!");
return "login";
}
}
/**
* 查询所有单据
*此control只有单权限认证
* @param model
* @return
*/
@RequiresPermissions("user:all")
@RequestMapping("/reportcheck/all/{status}")
public String reportcheckall(Model model, @PathVariable("status") String status)
{
String type = "all";
List<ReportTable> reportTables = reportService.findReportsByStatusAndReportType(STATUS_MAP.get(status), TYPES_MAP.get(type));
model.addAttribute("reporttables", reportTables);
model.addAttribute("status", status);
model.addAttribute("statustext", STATUS_MAP.get(status));
model.addAttribute("type", type);
model.addAttribute("typetext", TYPES_MAP.get(type));
return "report_check";
}
/**
* 查询表单
*这个是多权限的查询
* @param model
* @return
*/
***==这边千万注意,value中的值必须写成下面列表的形式,如果写错了权限无法赋予,老子为了2个引号浪费了2个小时在查原因,最后发现写成了value = {"user:tstable,user:all"},总是提示权限不足==***
//logical = Logical.OR 只要有其中一个权限就可以访问,and是两个需要同时具备
@RequiresPermissions(value = {"user:tstable","user:all"},logical = Logical.OR)
@RequestMapping("/reportcheck/ts/{status}")
public String reportcheckts(Model model, @PathVariable("status") String status)
{
String type = "ts";
List<ReportTable> reportTables = reportService.findReportsByStatusAndReportType(STATUS_MAP.get(status), TYPES_MAP.get(type));
model.addAttribute("reporttables", reportTables);
model.addAttribute("status", status);
model.addAttribute("statustext", STATUS_MAP.get(status));
model.addAttribute("type", type);
model.addAttribute("typetext", TYPES_MAP.get(type));
return "report_check";
}
这段代码为shiro跟thymeleaf整合的代码 shiro:hasPermission="user:all"
表示如果全下为user:all就可以看到这个空间,否则就看不到这个li标签
<ul class="nav nav-justified ulli">
<li shiro:hasPermission="user:all" class="badtype"><a href="reportcheck/all/all/">所有表单a>li>
<li shiro:hasPermission="user:tstable" class="badtype"><a href="reportcheck/ts/all/">tsa>li>
<li shiro:hasPermission="user:jbtable" class="badtype"><a href="reportcheck/jb/all/">jba>li>
<li shiro:hasPermission="user:sstable" class="badtype"><a href="reportcheck/ss/all/">ssa>li>
ul>
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 描述:
*
* @author caojing
* @create 2019-01-27-17:12
*/
@ControllerAdvice
public class NoPermissionException {
@ResponseBody
@ExceptionHandler(UnauthorizedException.class)
public String handleShiroException(Exception ex) {
return "亲,你没有权限噢!
";
}
}