因工作需要 项目开发新需求,需要加入权限,权限细化到每个按钮,实在是坑…以前怎么没用过shiro,本想着直接从session中拿user后台注入权限 不去登录,页面直接用标签控制权限。结果页面拿不到权限。猜测是权限匹配不到用户,还是做了登录。
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
方法里处理一下就OK了,
现登录模块是其他项目组(session共享) ,后续尝试从拦截器去做shiro登录验证;
1、pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- JSP begin -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- JSP end -->
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
2、项目配置文件 application.properties
server.port=9900
# 页面默认前缀目录
spring.mvc.view.prefix=/WEB-INF/jsp/
# 响应页面默认后缀
spring.mvc.view.suffix=.jsp
spring.mvc.date-format=yyyy-MM-dd
spring.jackson.date-format=yyyy-MM-dd
spring.jackson.time-zone=GMT+8
3、springboot 启动类 ShiroApplication
package vip.sweet.smile.shiro;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class ShiroApplication {
public static void main(String[] args) {
SpringApplication.run(ShiroApplication.class, args);
}
}
4 、shiro 认证 ShiroRealm
package vip.sweet.smile.shiro.auth;
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.stereotype.Component;
import vip.sweet.smile.shiro.pojo.Menu;
import vip.sweet.smile.shiro.pojo.Role;
import vip.sweet.smile.shiro.pojo.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class ShiroRealm extends AuthorizingRealm {
@Override
public String getName() {
return "shiroRealm";
}
/**
* 获取用户权限
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//从shiro中获取user对象
User user = (User) SecurityUtils.getSubject().getPrincipal();
// 根据 user对象从数据库中获取用户角色、权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//此处 简化查询角色信息(非本文重点) 直接构造角色
// 获取用户角色集
List<Role >roleList = new ArrayList<>();
Role role = new Role();
role.setRoleName("admin");
roleList.add(role);
Set<String> roleSet = roleList.stream().map(Role::getRoleName).collect(Collectors.toSet());
//设置用户角色 Set<String>
simpleAuthorizationInfo.setRoles(roleSet);
// 获取用户权限集
List<Menu> permissionList = new ArrayList<>();
Menu update = new Menu();
update.setMenuId(1L);
update.setPerms("dept:update");
permissionList.add(update);
Menu add = new Menu();
add.setMenuId(2L);
add.setPerms("dept:add");
permissionList.add(add);
Set<String> permissionSet = permissionList.stream().map(Menu::getPerms).collect(Collectors.toSet());
//设置用户权限 Set<String>
simpleAuthorizationInfo.setStringPermissions(permissionSet);
return simpleAuthorizationInfo;
}
/**
* 登录验证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//token中获取用户名密码
String username = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
//从数据库 根据用户名查询 用户信息(非重点略)
User user = new User();
user.setUsername(username);
user.setId(1);
// 这边如果验证不通过 则可以抛出异常 在登录接口可以捕获
/*if(user == null){
throw new AuthenticationException(“NO_USER”);
}*/
//创建 SimpleAuthenticationInfo会将用户信息放入shiro维护的用户集合
return new SimpleAuthenticationInfo(user, password, getName());
}
}
附 SimpleAuthenticationInfo 相关源码片段
public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {
this.principals = new SimplePrincipalCollection(principal, realmName);
this.credentials = credentials;
}
public SimplePrincipalCollection(Object principal, String realmName) {
if (principal instanceof Collection) {
this.addAll((Collection)principal, realmName);
} else {
this.add(principal, realmName);
}
}
public void addAll(Collection principals, String realmName) {
if (realmName == null) {
throw new IllegalArgumentException("realmName argument cannot be null.");
} else if (principals == null) {
throw new IllegalArgumentException("principals argument cannot be null.");
} else if (principals.isEmpty()) {
throw new IllegalArgumentException("principals argument cannot be an empty collection.");
} else {
this.cachedToString = null;
this.getPrincipalsLazy(realmName).addAll(principals);
}
}
5、shiro配置文件 ShiroConfig
package vip.sweet.smile.shiro.config;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import vip.sweet.smile.shiro.auth.ShiroRealm;
import java.util.LinkedHashMap;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置 securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 登录的URL
//shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后跳转的UR
//shiroFilterFactoryBean.setSuccessUrl("/index");
// 未授权URL
// shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 设置免认证 url
filterChainDefinitionMap.put("/index", "anon");
// 配置退出过滤器,其中具体的退出代码 Shiro已经替我们实现了
filterChainDefinitionMap.put("/login", "logout");
// 除上以外所有 url都必须认证通过才可以访问,未通过认证自动访问 LoginUrl
filterChainDefinitionMap.put("/**", "user");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager(ShiroRealm shiroRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 配置 SecurityManager,并注入 shiroRealm
securityManager.setRealm(shiroRealm);
// 配置 shiro session管理器
//securityManager.setSessionManager(sessionManager());
// 配置 缓存管理类 cacheManager
// securityManager.setCacheManager(cacheManager());
// 配置 rememberMeCookie
//securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
}
6、登录Controller IndexAction
package vip.sweet.smile.shiro.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class IndexAction {
@RequestMapping(value = "index")
public String toIndex(HttpServletRequest request){
//简化处理 没有任何判断 直接跳转 index页
//从前端获取用户名密码
String username = request.getParameter("username");
String password = request.getParameter("password");
UsernamePasswordToken upt = new UsernamePasswordToken(username,password);
//用户名 密码 token 调用 subject.login 方法登录将用户信息注入shiro
//会去调用ShiroRealm.doGetAuthenticationInfo(AuthenticationToken token) 验证用户信息
Subject subject = SecurityUtils.getSubject();
try{
subject.login(upt);
}catch(Exception e){
if("NO_USER".equals(e.getMessage())) return "noUser";
}
return "index";
}
}
7、JSP 页面 index
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<html>
<head>
<title>Title</title>
<script src="${ctx}/static/js/jquery-1.11.1.min.js"></script>
</head>
<body style="">
<span>[<shiro:principal type="vip.sweet.smile.shiro.pojo.User" property="username"/>]的主页</span>
<a onclick="" href="javascript:" style="float: right">注销登录</a>
<ul id="productCode">
<li value="role:add">role:add</li>
<li value="role:edit">role:edit</li>
<li value="menu:add">menu:add</li>
<shiro:hasPermission name="menu:edit"><li value="menu:edit"> menu:edit </li></shiro:hasPermission>
<shiro:hasPermission name="dept:add"><li value="menu:edit"> dept:add </li></shiro:hasPermission>
<shiro:hasPermission name="dept:update"><li value="source_na">dept:update</li></shiro:hasPermission>
<li value="user:add"> user:add </li>
<li value="user:edit">user:edit</li>
</ul>
<shiro:lacksPermission name="dept:update">dept:add</shiro:lacksPermission>
<div id="charts" style="width: 80%;height: 70%"></div>
<script type="text/javascript">
</script>
</body>
</html>
附:效果图