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

举报
yd_273762914 发表于 2020/12/02 22:42:17 2020/12/02
【摘要】 目前在企业级项目里做权限安全方面喜欢使用Apache开源的Shiro框架或者Spring框架的子框架Spring Security。 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。 Shiro框架具有轻便,开源的优点,所以本博客介绍基于Shiro的登录验证实现。 在maven里加入shiro需要的jar <!-...

目前在企业级项目里做权限安全方面喜欢使用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-->

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在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 -->


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

编写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);
	 }

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

在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  -->	

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

登录验证控制类实现:

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;
	}


}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188

前端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(); } } }); } }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

这里写图片描述

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

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

文章来源: smilenicky.blog.csdn.net,作者:smileNicky,版权归原作者所有,如需转载,请联系作者。

原文链接:smilenicky.blog.csdn.net/article/details/78307766

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。