Shiro 权限认证核心:
POM:文件:
<!--shiro-all-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 添加shrio-web支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.4</version>
</dependency>
<!-- 添加shrio-spring支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
WEB.XML:
<!--01.配置 Shiro 的 ShiroFilter-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
spring-shiro.xml 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 自定义Realm -->
<bean id="myRealm"
class="com.dsj.gdbd.controller.shiro.realm.MyRealm">
<property name="credentialsMatcher">
<bean
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value="1"></property>
</bean>
</property>
</bean>
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 注入realm -->
<property name="realm" ref="myRealm" />
</bean>
<!-- 开启Shiro注解 -->
<bean
class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- 重写Shiro登录过滤器 -->
<bean id="loginAgainFilter"
class="com.dsj.gdbd.controller.shiro.filter.MyFormAuthenticationFilter"></bean>
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager" />
<!-- 身份认证失败,则跳转到登录页面的配置(这里的路径与 form 表单路径一致,并且是 POST 请求) -->
<property name="loginUrl" value="/login/to_login" />
<!-- 权限认证失败,则跳转到指定页面 -->
<property name="unauthorizedUrl"
value="/login/to_unauthorized" />
<!-- 权限认证成功,则跳转到指定页面 -->
<property name="successUrl" value="/home/to_index" />
<property name="filters">
<map>
<entry key="mauthc" value-ref="loginAgainFilter" />
<entry key="logout">
<!-- 退出之后的重定向地址 -->
<bean class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value="/login/to_login" />
</bean>
</entry>
</map>
</property>
<property name="filterChainDefinitions">
<value>
<!-- anon 表示可以匿名使用。 -->
/static/**=anon
/login/to_login=mauthc
/login/logout=logout
/login/**=anon
<!-- authc表示需要认证(登录)才能使用 -->
/** = authc
</value>
</property>
</bean>
</beans>
重写Shiro登录过滤器 :
package com.dsj.gdbd.controller.shiro.filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
//重写登录成功
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
ServletResponse response) throws Exception {
//开启授权
subject.hasRole("*");
return super.onLoginSuccess(token, subject, request, response);
}
}
MyRealm.java 验证授权:
package com.dsj.gdbd.controller.shiro.realm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.dsj.gdbd.pojo.MenuFunction;
import com.dsj.gdbd.pojo.RoleInfo;
import com.dsj.gdbd.pojo.UserInfo;
import com.dsj.gdbd.service.MenuFunctionService;
import com.dsj.gdbd.service.RoleInfoService;
import com.dsj.gdbd.service.UserInfoService;
import com.dsj.gdbd.utils.enums.DeleteStatusEnum;
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserInfoService userInfoService;
@Autowired
private RoleInfoService roleInfoService;
@Autowired
private MenuFunctionService menuFunctionService;
private final Logger LOGGER = LoggerFactory.getLogger(MyRealm.class);
@SuppressWarnings("unchecked")
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
/**
*
* 流程 1.根据用户user->2.获取角色id->3.根据角色id获取权限
*/
// 01、获取用户登陆ing
String realName = (String) principals.getPrimaryPrincipal();
LOGGER.info("realName{}", realName);
// 02、设置查询条件
UserInfo info = new UserInfo();
info.setRealName(realName);
info.setDelFlag(DeleteStatusEnum.NDEL.getValue());
// 03、查询对象信息
UserInfo userInfo = userInfoService.getInfo(info);
LOGGER.info("admin.id{}", userInfo.getId());
LOGGER.info("admin.name{}", userInfo.getUserName());
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 04、获取用户下的所有角色
List<RoleInfo> rolelist = roleInfoService.getRoles(userInfo.getId());
// 获取所有角色的 Id
List<Long> rolesIds = new ArrayList<Long>();
for (RoleInfo item : rolelist) {
rolesIds.add(item.getId());
}
// 05、角色下所拥有的所有权限
List<MenuFunction> listMenus = menuFunctionService.getListMenus(rolesIds);
// 获取访问的权限
List<String> patterns = new ArrayList<String>();
for (MenuFunction item : listMenus) {
patterns.add(item.getPattern());
}
// 06、设置绑定 分类级别关系
List<MenuFunction> menuFunction = menuFunction(listMenus);
// 07、去掉空的权限
List<MenuFunction> notNullMenus = notNull(menuFunction);
// 08、权限菜单集合保存在Session 回话中
SecurityUtils.getSubject().getSession().setAttribute("menus", notNullMenus);
// 09、当前用户所拥有的所有权限保存在 session 会话中进行对比
SecurityUtils.getSubject().getSession().setAttribute("menusPatterns", patterns);
// 10、当前登录的用户信息
SecurityUtils.getSubject().getSession().setAttribute("sessionUser", userInfo);
// 11、将用户拥有的权限保存在 shiro中 用于后期页面的权限验证
authorizationInfo.addStringPermissions(
(List<String>) SecurityUtils.getSubject().getSession().getAttribute("menusPatterns"));
return authorizationInfo;
}
/***
* 认证方法 验证账号密码
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
System.out.println("进行验证了");
// 01、获取登录用户名
String realName = (String) authenticationToken.getPrincipal();
// 02、设置条件
UserInfo info = new UserInfo();
info.setRealName(realName);
info.setDelFlag(DeleteStatusEnum.NDEL.getValue());
// 03、查询对象信息
UserInfo userInfo = userInfoService.getInfo(info);
if (userInfo == null) {
throw new UnknownAccountException();
}
// 最后的比对需要交给安全管理器
// 三个参数进行初步的简单认证信息对象的包装(验证密码)
SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(userInfo.getRealName(), userInfo.getUserPwd(),
this.getName());
return authcInfo;
}
/***
* 执行遍历
*
* @param menus
* 所有权限列表集合
* @param list
* 指定角色查询到的 权限Id
* @return
*/
@SuppressWarnings("unused")
private List<MenuFunction> menuFunction(List<MenuFunction> menus) {
// 中转集合
List<MenuFunction> functions = null;
try {
functions = new ArrayList<MenuFunction>();
// 循环遍历菜单层级关系
// 循环遍历
for (MenuFunction item : menus) {
// 获取pid
long pid = item.getPid();
if (pid == 0) {
// 遍历一级分类
functions.add(item);
} else {
for (MenuFunction innerCate : menus) {
/***
* 外层循环 pid 没有的等于0 的话 获取当前对象的 id 作为一级
*/
Long id = innerCate.getId();
if (id == pid) {
innerCate.getChildren().add(item);
break;
}
}
}
}
} catch (Exception e) {
LOGGER.error("循环遍历层级关系失败!!!" + e);
}
return functions;
}
/***
* 去掉空的权限
*
* @param list
* @return
*/
private List<MenuFunction> notNull(List<MenuFunction> list) {
List<MenuFunction> menusList = null;
try {
// 去掉空的权限
menusList = new ArrayList<MenuFunction>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getChildren().size() != 0) {
menusList.add(list.get(i));
notNull(list.get(i).getChildren());
}
}
} catch (Exception e) {
LOGGER.error("去除空的权限时意外出错!!!" + e);
}
return menusList;
}
}
Controller 关键代码:
package com.dsj.gdbd.controller.login;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/***
* 登陆
* @author asus
*
*/
@Controller
@RequestMapping("login")
public class LoginController {
/***
* 跳转登录页
* @return
*/
@RequestMapping("to_login")
public String login() {
return "login/login";
}
}
package com.dsj.gdbd.controller.home;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("home")
public class HomeController {
/***
* 跳转主页面
* @return
*/
@RequestMapping("to_index")
public String login() {
return "home/welcome";
}
}
login.jsp:登录页:(重点关注 form 表单 与 异常处理 )
<%@ page contentType="text/html;charset=UTF-8"%>
<%@include file="/WEB-INF/jsp/common/taglibs.jspf"%>
<html lang="en">
<head>
<link rel="stylesheet" href="${ctx}/static/front/css/login/style.css">
<link rel="stylesheet"
href="${ctx}/static/front/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="${ctx}/static/front/js/jquery.min.js"></script>
<script src="${ctx}/static/front/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src='${ctx}/static/front/js/style.js'></script>
<script type="text/javascript">
var _ctx = '${ctx}';
</script>
<title>登录</title>
</head>
<style>
</style>
<body>
<!-- <div class="bj"> -->
<header>
<img src="${ctx}/static/front/images/login/logo.png" alt="">
</header>
<!-- </div> -->
<div class="city">
<img src="${ctx}/static/front/images/login/4.png" alt="">
<div class="denglu">
<div class="titBian">
<span class="tit">用户登录</span>
</div>
<form id="loginForm" action="${ctx }/login/to_login" method="post">
<div class="fengexian"></div>
<div class=" alert-danger dengLuTiShi" id="errorDiv">
<span class="dengLuTiShiTu glyphicon glyphicon-minus-sign"></span><span
id="error" class="cuo">${errormsg }</span>
</div>
<div class="input-group name">
<span class="input-group-addon tx1" id="basic-addon1"><img
id="tx" class="tupian"
src="${ctx}/static/front/images/login/tuyiyi-com-0.png" alt=""></span>
<input type="text" id="phone" οnclick="phone2()" name="username"
class="form-control" autocomplete="off" placeholder="请输入手机号或账号"
aria-describedby="basic-addon1"> <span
class="input-group-addon cha1" id="cha" οnclick="qingkong()">X</span>
</div>
<div class="input-group password">
<span class="input-group-addon tx1" id="basic-addon2"><img
src="${ctx}/static/front/images/login/7.png" id="mm"
class="tupian" alt=""></span> <input type="password" id="mima"
name="password" class="form-control" οnclick="mma()"
autocomplete="off" placeholder="请输入密码"
aria-describedby="basic-addon1">
</div>
<span class="wangjimima" οnclick="wangji()">忘记密码</span>
<button id="login_btn" type="button" class="btn btn-primary btnDL">登录</button>
</form>
<%
//shiro 获取异常,判断异常类型
Object errorClass = request.getAttribute("shiroLoginFailure");
if ("org.apache.shiro.authc.IncorrectCredentialsException".equals(errorClass)) {
request.setAttribute("errormsg", "用户名或密码错误");
}
if ("org.apache.shiro.authc.UnknownAccountException".equals(errorClass)) {
request.setAttribute("errormsg", "用户不存在或已禁用");
}
if ("com.dsj.data.shiro.filter.VerifyCodeException".equals(errorClass)) {
request.setAttribute("errormsg", "验证码不正确");
}
%>
</div>
</div>
<div class="yun">
<div class="kuanCont">
<a class="kuan"> 联系我们xxxxx </a> <a
class="kuan kuanLast"> 北京xxxxx技术服务有限公司 </a>
</div>
</div>
<script type="text/javascript">
$(function() {
$("#login_btn").off().on("click", function() {
$("#loginForm").submit();
});
if ('${errormsg }' != '') {
var errorDiv = document.getElementById('errorDiv');
$("#error").html("${errormsg }");
errorDiv.style.visibility = 'visible';
}
})
$(document).keydown(function(event) {
if (event.keyCode == 13) { //绑定回车
$('#login_btn').click();
}
});
</script>
<script src="${ctx }/static/back/login/login.js"></script>
</body>
</html>
其他 相关 Shiro 权限 Demo:案例Demo并不是很完整,你只需要拿走里面你需要的配置就好。