web.xml配置
<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>
shiro的配置文件(bean-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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 自定义表单认证过滤器 com.panda.contorller.shiro.MyFormAuthenticationFilter(见后面)-->
<bean id="myFormAuthenticationFilter" class="com.panda.contorller.shiro.MyFormAuthenticationFilter">
<property name="usernameParam" value="username"></property>
<property name="passwordParam" value="password"></property>
<property name="rememberMeParam" value="rememberMe"></property>
</bean>
<!-- shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="loginUrl" value="/login"></property>
<property name="unauthorizedUrl" value="/refuse.jsp"></property>
<property name="successUrl" value="/index"></property>
<property name="securityManager" ref="securityManager"></property>
<!-- 自定义filter -->
<property name="filters">
<map>
<entry key="authc" value-ref="myFormAuthenticationFilter" />
</map>
</property>
<property name="filterChainDefinitions">
<value>
/logout.action=logout
/images/**=anon
/js/**=anon
/script/**=anon
/style/**=anon
/themes/**=anon
/charts/**=anon
<!-- /login.jsp=anon -->
/images/image.jsp=anon
/**=authc
</value>
</property>
</bean>
<!-- 配置安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm"></property>
</bean>
<!-- 配置realm -->
<bean id="customRealm" class="com.panda.service.realm.CustomRealm">
<!-- <property name="credentialsMatcher" ref="credentialsMatcher"></property> -->
</bean>
<!-- 配置凭证匹配器,md5加密 -->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5"></property>
<property name="hashIterations" value="1"></property>
</bean>
</beans>
一个简单的验证码生成(jsp页面)
<%@ page language="java" contentType="text/html; charset=UTF-8" import="java.awt.*, java.awt.image.*,java.util.*,javax.imageio.*"
pageEncoding="UTF-8"%>
<%!Color getRandColor(int fc, int bc) {
Random random = new Random();
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}%>
<%
out.clear();
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
int width = 60, height = 20;
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
Random random = new Random();
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
g.setFont(new Font("Times New Roman", Font.PLAIN, 18));
g.setColor(getRandColor(160, 200));
for (int i = 0; i < 155; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x, y, x + xl, y + yl);
}
String sRand = "";
for (int i = 0; i < 4; i++) {
String rand = String.valueOf(random.nextInt(10));
sRand += rand;
g.setColor(new Color(20 + random.nextInt(110), 20 + random
.nextInt(110), 20 + random.nextInt(110)));
g.drawString(rand, 13 * i + 6, 16);
}
// 将验证码存入SESSION
session.setAttribute("sRand", sRand);
g.dispose();
ImageIO.write(image, "JPEG", response.getOutputStream());
%>
from表单
<form id="loginForm" action="${ctx}/login" method="post" >
用户名:
<input type="text" name="username" value="123" style="background-color: white;border: 1px solid #a9a9a9" id="userName" size="20" maxlength="20">
密码:
<input name="password" id="pwd" value="123" style="background-color: white;border: 1px solid #a9a9a9" type="password" size="20" maxlength="20">
验证码:
<input type="text" value="1" style="background-color: white;border: 1px solid #a9a9a9" name="imageCode" class="txtCode" id="imageCode" size="10" />
<img onclick="javascript:loadimage();" title="换一张试试" name="randImage" id="randImage" src="${ctx}/images/image.jsp" width="60" height="20" border="1" align="absmiddle">
</form>
登录的controller
package com.panda.contorller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/*import org.apache.commons.lang3.StringUtils;*/
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import com.panda.pojo.Menu;
import com.panda.pojo.MenuAndPower;
import com.panda.pojo.User;
import com.panda.service.impl.MenuService;
@Controller
public class IndexController {
@Autowired
private MenuService menuService = null;
/**
* 登陆成功后进入这里,获取用户信息和菜单权限
* @param model
* @param session
* @return
*/
@RequestMapping("/index")
public String first(Model model,HttpSession session) {
Subject subject = SecurityUtils.getSubject();//第一步:获取我们的主体
User user = (User) subject.getPrincipal();
session.setAttribute("userId",user.getUser_id());
model.addAttribute("userActive", user); //将数据放置到域对象
//菜单转化为自定义的json
SimplePropertyPreFilter filter = new SimplePropertyPreFilter(MenuAndPower.class, "id","pId","text","url");
String json = JSON.toJSONString(user.getMenuAndPowers(), filter);
model.addAttribute("menu", json);
return "main2.jsp";
}
/**
* 登陆失败的处理
* @param request
* @param session
* @return
*/
@RequestMapping("/login")
public String login(HttpServletRequest request,HttpSession session) {
// 获取我们的错误信息
String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
//方法一
/*if(UnknownAccountException.class.getName().equals(exceptionClassName)) {
request.setAttribute("logError", "用户名不存在");
}*/
//方法二时
if(null!=exceptionClassName){
if(exceptionClassName.equals("randomCodeError")) {
request.setAttribute("logError", "验证码错误!");
return "login.jsp";
}
if(exceptionClassName.equals("org.apache.shiro.authc.UnknownAccountException")||exceptionClassName.equals("org.apache.shiro.authc.IncorrectCredentialsException")){
request.setAttribute("logError", "用户名或密码错误");
}
}
return "login.jsp";
}
}
自定义的realm,认证登录信息
package com.panda.service.realm;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.Service;
import com.panda.pojo.MenuAndPower;
import com.panda.pojo.User;
import com.panda.repository.MenuAndPowerRepository;
import com.panda.repository.UserRepository;
@Service
public class CustomRealm extends AuthorizingRealm {
@Override
public String getName() {
return super.getName();
}
@Resource
private MenuAndPowerRepository menuAndPowerRepository = null;
@Resource
private UserRepository userRepository = null;
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();//获取表单的用户名
User user=null;
try {
user = userRepository.queryByUsername(username);//从数据库查询用户
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (user == null) {
return null;
}
User userActive = new User();
List<MenuAndPower> menus = new ArrayList<>();
try {
menus = menuAndPowerRepository.queryMenuByUserId(user.getUser_id());//获取该用户的菜单
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//将用户信息和菜单放入对象
userActive.setUser_id(user.getUser_id());
userActive.setUser_name(username);
userActive.setMenuAndPowers(menus);
//System.out.println(menus);
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userActive, user.getPassword(),
getName());
return simpleAuthenticationInfo;
}
}
继承shiro的FormAuthenticationFilter类 ,重写里面的一些方法。实现shiro登录跳转到指定页面,验证码的实现,不注销之前已登录用户下,重新登录
MyFormAuthenticationFilter类
package com.panda.contorller.shiro;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import com.panda.pojo.User;
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
/**
* 每次登录都会到这里来,这里用来处理 不注销之前已登录用户下,再次登录
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (isLoginRequest(request, response))
{
if (isLoginSubmission(request, response))
{
//本次用户登陆账号
String account = this.getUsername(request);
Subject subject = this.getSubject(request, response);
//之前登陆的用户
User user = (User) subject.getPrincipal();
//如果两次登陆的用户不一样,则先退出之前登陆的用户,(有问题,相同用户无法跳转页面)解决:可以不判断,都退出之前的登录,再重新登录
if (account != null && user != null && !account.equals(user.getUser_name()))
{
//获取session,获取验证码
HttpServletRequest httpServletRequest=(HttpServletRequest) request;
HttpSession session= httpServletRequest.getSession();
String sRand = (String) session.getAttribute("sRand");
//注销登录,同时会使session失效
subject.logout();
//所以重新设置session
HttpSession session1= httpServletRequest.getSession();
session1.setAttribute("sRand", sRand);
}
}
}
return super.isAccessAllowed(request, response, mappedValue);
}
/**
* 重写FormAuthenticationFilter的onLoginSuccess方法
* 指定的url传递进去,这样就实现了跳转到指定的页面;
*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
ServletResponse response) throws Exception {
WebUtils.getAndClearSavedRequest(request);//清理了session中保存的请求信息
WebUtils.redirectToSavedRequest(request, response, getSuccessUrl());
return false;
}
/**
* 验证码验证
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest=(HttpServletRequest) request;
//从session获取验证码,正确的验证码
HttpSession session=httpServletRequest.getSession();
String validate =(String) session.getAttribute("sRand");
//获取输入的验证码
String myValidate = httpServletRequest.getParameter("imageCode");
//验证失败,设置错误信息
if (validate!=null&& myValidate!=null&&!validate.equals(myValidate)) {
httpServletRequest.setAttribute("shiroLoginFailure", "randomCodeError");
//拒绝访问
return true;
}
return super.onAccessDenied(request, response);
}
}