关闭

基于权限安全框架Shiro的登录验证功能实现

标签: spring
526人阅读 评论(0) 收藏 举报
分类:

目前在企业级项目里做权限安全方面喜欢使用Apache开源的Shiro框架或者Spring框架的子框架Spring Security。

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。

Shiro框架具有轻便,开源的优点,所以本博客介绍基于Shiro的登录验证实现。

在maven里加入shiro需要的jar

<!--shiro start-->
      <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>1.2.3</version>
       </dependency>
<!-- shiro end-->

在web.xml加上Shiro过滤器配置:


  <!-- Shiro过滤器配置 start -->
   <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过滤器配置 end -->

编写shiro的ShiroRealm类:

package org.muses.jeeplatform.core.security.shiro;

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.LockedAccountException;
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.muses.jeeplatform.model.entity.User;
import org.muses.jeeplatform.service.UserService;

/**
 * @description 基于Shiro框架的权限安全认证和授权
 * @author Nicky
 * @date 2017年3月12日
 */
public class ShiroRealm extends AuthorizingRealm {

    /**注解引入业务类**/
    @Resource
    UserService userService;

    /**
     * 登录信息和用户验证信息验证(non-Javadoc)
     * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(AuthenticationToken)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

         String username = (String)token.getPrincipal();                //得到用户名 
         String password = new String((char[])token.getCredentials());  //得到密码

         User user = userService.findByUsername(username);

         /**检测是否有此用户 **/
         if(user == null){
             throw new UnknownAccountException();//没有找到账号异常
         }
         /**检验账号是否被锁定 **/
         if(Boolean.TRUE.equals(user.getLocked())){
             throw new LockedAccountException();//抛出账号锁定异常
         }
         /**AuthenticatingRealm使用CredentialsMatcher进行密码匹配**/
         if(null != username && null != password){
             return new SimpleAuthenticationInfo(username, password, getName());
         }else{
             return null;
         }

    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法(non-Javadoc)
     * @see AuthorizingRealm#doGetAuthorizationInfo(PrincipalCollection)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        String username = (String)pc.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userService.getRoles(username));
        authorizationInfo.setStringPermissions(userService.getPermissions(username));
        System.out.println("Shiro授权");
        return authorizationInfo;
    }

     @Override
     public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
         super.clearCachedAuthorizationInfo(principals);
     }

     @Override
     public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
         super.clearCachedAuthenticationInfo(principals);
     }

     @Override
     public void clearCache(PrincipalCollection principals) {
          super.clearCache(principals);
     }

}

在Spring框架里集成Shiro,加入配置

<!--  Shiro start  -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="ShiroRealm" />
        </bean>

        <!-- 项目自定义的Realm -->
        <bean id="ShiroRealm" class="org.muses.jeeplatform.core.security.shiro.ShiroRealm" ></bean>

        <!-- Shiro Filter -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />

            <property name="loginUrl" value="/login" />

            <property name="successUrl" value="/admin/index" />

            <property name="unauthorizedUrl" value="/login" />

            <property name="filterChainDefinitions">
                <value>
                /static/**                  = anon
                /upload/**                  = anon
                /plugins/**                 = anon
                /code                       = anon
                /login                      = anon
                /logincheck                 = anon
                /**                         = authc
                </value>
            </property>
        </bean>
    <!--  Shiro end  -->    

登录验证控制类实现:

package org.muses.jeeplatform.web.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.muses.jeeplatform.core.Constants;
import org.muses.jeeplatform.model.entity.Menu;
import org.muses.jeeplatform.model.entity.Permission;
import org.muses.jeeplatform.model.entity.Role;
import org.muses.jeeplatform.model.entity.User;
import org.muses.jeeplatform.service.MenuService;
import org.muses.jeeplatform.service.UserService;
import org.muses.jeeplatform.utils.Tools;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

/**
 * @description 登录操作的控制类,使用Shiro框架,做好了登录的权限安全认证,
 * getRemortIP()方法获取用户登录时的ip并保存到数据库
 * @author Nicky
 * @date 2017年3月15日
 */
@Controller
public class LoginController extends BaseController {

    @Autowired
    UserService userService;
    @Autowired
    MenuService menuService;

    /**
     * 获取登录用户的IP
     * @throws Exception 
     */
    public void getRemortIP(String username)  {  
        HttpServletRequest request = this.getRequest();
        Map<String,String> map = new HashMap<String,String>();
        String ip = "";
        if (request.getHeader("x-forwarded-for") == null) {  
            ip = request.getRemoteAddr();  
        }else{
            ip = request.getHeader("x-forwarded-for");  
        }
        map.put("username", username);
        map.put("loginIp", ip);
         userService.saveIP(map);
    }  

    /**
     * 访问后台登录页面
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/login",produces="text/html;charset=UTF-8")
    public ModelAndView toLogin()throws ClassNotFoundException{
        ModelAndView mv = this.getModelAndView();
        mv.setViewName("admin/frame/login");
        return mv;
    }

    /**
     * 基于Shiro框架的登录验证,页面发送JSON请求数据,
     * 服务端进行登录验证之后,返回Json响应数据,"success"表示验证成功
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/logincheck", produces="application/json;charset=UTF-8")
    @ResponseBody
    public String loginCheck(HttpServletRequest request)throws AuthenticationException{
        JSONObject obj = new JSONObject();
        String errInfo = "";//错误信息
        String logindata[] = request.getParameter("LOGINDATA").split(",");
        if(logindata != null && logindata.length == 3){
            //获取Shiro管理的Session
            Subject subject = SecurityUtils.getSubject();
            Session session = subject.getSession();
            String codeSession = (String)session.getAttribute(Constants.SESSION_SECURITY_CODE);
            String code = logindata[2]; 
            /**检测页面验证码是否为空,调用工具类检测**/
            if(Tools.isEmpty(code)){
                errInfo = "nullcode";
            }else{
                String username = logindata[0];
                String password = logindata[1];
                if(Tools.isNotEmpty(codeSession) && codeSession.equalsIgnoreCase(code)){
                    //Shiro框架SHA加密
                    String passwordsha = new SimpleHash("SHA-1",username,password).toString();
                    System.out.println(passwordsha);
                    //检测用户名和密码是否正确
                    User user = userService.doLoginCheck(username,passwordsha);
                    if(user != null){
                        if(Boolean.TRUE.equals(user.getLocked())){
                            errInfo = "locked";
                        }else{
                            //Shiro添加会话
                            session.setAttribute("username", username);
                            session.setAttribute(Constants.SESSION_USER, user);
                            //删除验证码Session
                            session.removeAttribute(Constants.SESSION_SECURITY_CODE);
                            //保存登录IP
                            getRemortIP(username);
                            /**Shiro加入身份验证**/
                            Subject sub = SecurityUtils.getSubject();
                            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
                            sub.login(token);
                        }
                    }else{
                        //账号或者密码错误
                        errInfo = "uerror";
                    }
                    if(Tools.isEmpty(errInfo)){
                        errInfo = "success";
                    }
                }else{
                    //缺少参数
                    errInfo="codeerror";
                }
            }
        }
        obj.put("result", errInfo);
        return obj.toString();
    }

    /**
     * 后台管理系统主页
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/admin/index")
    public ModelAndView toMain() throws AuthenticationException{
        ModelAndView mv = this.getModelAndView();
        /**获取Shiro管理的Session**/
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        User user = (User)session.getAttribute(Constants.SESSION_USER);

        if(user != null){
            ...//业务实现
        }else{
            //会话失效,返回登录界面
            mv.setViewName("admin/frame/login");
        }
        mv.setViewName("admin/frame/index");
        return mv;
    }

    /**
     * 注销登录
     * @return
     */
    @RequestMapping(value="/logout")
    public ModelAndView logout(){
        ModelAndView mv = this.getModelAndView();
        /**Shiro管理Session**/
        Subject sub = SecurityUtils.getSubject();
        Session session = sub.getSession();
        session.removeAttribute(Constants.SESSION_USER);
        session.removeAttribute(Constants.SESSION_SECURITY_CODE);
        /**Shiro销毁登录**/
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        /**返回后台系统登录界面**/
        mv.setViewName("admin/frame/login");
        return mv;
    }


}

前端Ajax和JQeury校验实现:

 /**客户端校验**/
    function checkValidity() {

        if ($("#username").val() == "") {

            $("#username").tips({
                side : 2,
                msg : '用户名不得为空',
                bg : '#AE81FF',
                time : 3
            });

            $("#username").focus();
            return false;
        }

        if ($("#password").val() == "") {
            $("#password").tips({
                side : 2,
                msg : '密码不得为空',
                bg : '#AE81FF',
                time : 3
            });

            $("#password").focus();
            return false;
        }
        if ($("#code").val() == "") {

            $("#code").tips({
                side : 1,
                msg : '验证码不得为空',
                bg : '#AE81FF',
                time : 3
            });

            $("#code").focus();
            return false;
        }

        return true;
    }

    /**服务器校验**/
    function loginCheck(){
        if(checkValidity()){
            var username = $("#username").val();
            var password = $("#password").val();
            var code = username+","+password+","+$("#code").val();
            $.ajax({
                type: "POST",//请求方式为POST
                url: 'logincheck',//检验url
                data: {LOGINDATA:code,tm:new Date().getTime()},//请求数据
                dataType:'json',//数据类型为JSON类型
                cache: false,//关闭缓存
                success: function(data){//响应成功
                    if("success" == data.result){
                        $("#login").tips({
                            side : 1,
                            msg : '正在登录 , 请稍后 ...',
                            bg : '#68B500',
                            time : 10
                        });
                        window.location.href="admin/index";
                    }else if("uerror" == data.result){
                        $("#username").tips({
                            side : 1,
                            msg : "用户名或密码有误",
                            bg : '#FF5080',
                            time : 15
                        });
                        $("#username").focus();
                    }else if("codeerror" == data.result){
                        $("#code").tips({
                            side : 1,
                            msg : "验证码输入有误",
                            bg : '#FF5080',
                            time : 15
                        });
                        $("#code").focus();
                    }else if("locked" == data.result){
                        alert('您的账号被锁定了,呜呜');
                    }else{
                        $("#username").tips({
                            side : 1,
                            msg : "缺少参数",
                            bg : '#FF5080',
                            time : 15
                        });
                        $("#username").focus();
                    }
                }
            });
        }
    }

这里写图片描述

登录成功,Session会话过期,需要重新登录,保证系统安全性
这里写图片描述

本博客只提供基于Shiro的登录验证实现,具体代码可以去我的github下载:https://github.com/u014427391/jeeplatform
欢迎star

1
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

shiro-springmvc-mybatis登录认证 权限控制

shiro-springmvc权限控制
  • wangbo54979
  • wangbo54979
  • 2016-07-28 08:51
  • 8147

Shiro安全框架入门篇(登录验证实例详解与源码)

一、Shiro框架简单介绍Apache Shiro是Java的一个安全框架,旨在简化身份验证和授权。Shiro在JavaSE和JavaEE项目中都可以使用。它主要用来处理身份认证,授权,企业会话管理和...
  • u013142781
  • u013142781
  • 2016-02-03 15:23
  • 73371

shiro 权限框架认证和授权原理介绍

Shiro是一个安全框架,是Apache 的一个子项目。Shiro提供了:认证、授权、加密、会话管理、与Web集成、缓存等模块。
  • QQ994406030
  • QQ994406030
  • 2016-12-20 19:28
  • 6413

Jeeplus框架SSM+shiro权限控制中实现跳过登录验证访问接口数据

新项目中用的Jeeplus框架,里面用的shiro权限控制,特别好用,但是如果单独写接口的话,总是会有登录验证,下面上思路实现一行代码让任意接口跳过登录限制。 正常代码生成机生成的代码不管它,这是每个...
  • qq_16497617
  • qq_16497617
  • 2016-09-18 19:59
  • 5990

Maven+SSM+Shiro框架整合完整实现,实现某权限用户登录,记住密码,验证码等功能。

  • 2017-12-22 08:42
  • 216KB
  • 下载

Shiro安全框架入门篇(登录验证实例详解与源码)

一、Shiro框架简单介绍 Apache Shiro是Java的一个安全框架,旨在简化身份验证和授权。Shiro在JavaSE和JavaEE项目中都可以使用。它主要用来处理身份认证,授权,企...
  • muxiayayoumei
  • muxiayayoumei
  • 2016-05-25 10:03
  • 2275

Shiro安全框架入门篇(登录验证实例详解与源码)

一、Shiro框架简单介绍 Apache Shiro是Java的一个安全框架,旨在简化身份验证和授权。Shiro在JavaSE和JavaEE项目中都可以使用。它主要用来处理身份认证,授权,企业会话管...
  • okkeqin
  • okkeqin
  • 2017-01-16 00:00
  • 294

Maven+SSM+Shiro框架整合实现某权限用户登录,记住密码等功能。

  • 2017-12-20 08:34
  • 215KB
  • 下载

Maven+SSM+Shiro框架整合完整实现,实现某权限用户登录,记住密码等功能。

  • 2017-12-15 10:14
  • 214KB
  • 下载

shiro 用户权限管理(2)-----注册md5加密,登录验证

register.jsp注册页面: <form action="/main/add" method="post"> 姓 名: 密 码:<input...
  • fengcai0123
  • fengcai0123
  • 2017-06-30 17:22
  • 973
    个人资料
    • 访问:488167次
    • 积分:5351
    • 等级:
    • 排名:第5898名
    • 原创:123篇
    • 转载:7篇
    • 译文:6篇
    • 评论:257条
    About Me
    Turtles
    Clock
    博客专栏