热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Shiro系列之的登录验证功能实现

目前在企业级项目里做权限安全方面喜欢使用Apache开源的Shiro框架或者Spring框架的子框架SpringSecurity。ApacheShiro是一个强大且易用的Java

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

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

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

在maven里加入shiro需要的jar

org.apache.shiroshiro-all1.2.3

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

shiroFilterorg.springframework.web.filter.DelegatingFilterProxytargetFilterLifecycletrueshiroFilter/*

编写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 {/**注解引入业务类**/@ResourceUserService userService;/*** 登录信息和用户验证信息验证(non-Javadoc)* @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(AuthenticationToken)*/@Overrideprotected 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)*/@Overrideprotected 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;}@Overridepublic void clearCachedAuthorizationInfo(PrincipalCollection principals) {super.clearCachedAuthorizationInfo(principals);}@Overridepublic void clearCachedAuthenticationInfo(PrincipalCollection principals) {super.clearCachedAuthenticationInfo(principals);}@Overridepublic void clearCache(PrincipalCollection principals) {super.clearCache(principals);}}

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

/static/** = anon/upload/** = anon/plugins/** = anon/code = anon/login = anon/logincheck = anon/** = authc

登录验证控制类实现:

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 {@AutowiredUserService userService;@AutowiredMenuService menuService;/*** 获取登录用户的IP* @throws Exception */public void getRemortIP(String username) { HttpServletRequest request = this.getRequest();Map map = new HashMap();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")@ResponseBodypublic 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管理的SessionSubject 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);//删除验证码Sessionsession.removeAttribute(Constants.SESSION_SECURITY_CODE);//保存登录IPgetRemortIP(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",//请求方式为POSTurl: 'logincheck',//检验urldata: {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


推荐阅读
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 标题: ... [详细]
  • 本文讨论了在shiro java配置中加入Shiro listener后启动失败的问题。作者引入了一系列jar包,并在web.xml中配置了相关内容,但启动后却无法正常运行。文章提供了具体引入的jar包和web.xml的配置内容,并指出可能的错误原因。该问题可能与jar包版本不兼容、web.xml配置错误等有关。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文讨论了在Spring 3.1中,数据源未能自动连接到@Configuration类的错误原因,并提供了解决方法。作者发现了错误的原因,并在代码中手动定义了PersistenceAnnotationBeanPostProcessor。作者删除了该定义后,问题得到解决。此外,作者还指出了默认的PersistenceAnnotationBeanPostProcessor的注册方式,并提供了自定义该bean定义的方法。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • Activiti7流程定义开发笔记
    本文介绍了Activiti7流程定义的开发笔记,包括流程定义的概念、使用activiti-explorer和activiti-eclipse-designer进行建模的方式,以及生成流程图的方法。还介绍了流程定义部署的概念和步骤,包括将bpmn和png文件添加部署到activiti数据库中的方法,以及使用ZIP包进行部署的方式。同时还提到了activiti.cfg.xml文件的作用。 ... [详细]
  • 本文介绍了安全性要求高的真正密码随机数生成器的概念和原理。首先解释了统计学意义上的伪随机数和真随机数的区别,以及伪随机数在密码学安全中的应用。然后讨论了真随机数的定义和产生方法,并指出了实际情况下真随机数的不可预测性和复杂性。最后介绍了随机数生成器的概念和方法。 ... [详细]
  • 大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记
    本文介绍了大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记,包括outputFormat接口实现类、自定义outputFormat步骤和案例。案例中将包含nty的日志输出到nty.log文件,其他日志输出到other.log文件。同时提供了一些相关网址供参考。 ... [详细]
  • 本文介绍了Windows Vista操作系统中的用户账户保护功能,该功能是为了增强系统的安全性而设计的。通过对Vista测试版的体验,可以看到系统在安全性方面的进步。该功能的引入,为用户的账户安全提供了更好的保障。 ... [详细]
author-avatar
卡布基诺2502934121
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有