您的位置:首页 > 其它

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

2017-10-22 01:21 1296 查看
目前在企业级项目里做权限安全方面喜欢使用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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐