shiro登录验证(登录跳转到指定页面,验证码验证,不注销之前已登录用户下,再次登录)

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" />&nbsp; &nbsp; 

<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);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值