shiro 前后端分离框架 用户登录解决方案

介绍

最近公司要原本springmvc+shiro 权限控制的一个项目,改为前后端分离的,使前端人员能有更多时间来做前端的交互工作,提升用户体验。

但是这个问题就来了,原来没有分离的情况下,shiro 权限是通过凭证来登录的,现在需要更改为前端ajax提交登录信息来登录,于是更改了shiro的登录方式,这里做一个记录。

@RequestMapping(value="/userLogin",method=RequestMethod.GET)
    @ResponseBody
    public ResultSuperApp superAppLogin(HttpServletRequest request) throws Exception{
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String error="未知错误异常";
        if(null == username || null == password ){
            return ResultSuperApp.getFailureInstance("参数为空", 300);
        }
        try {
            Subject currentUser = SecurityUtils.getSubject();  
            UsernamePasswordToken token = new UsernamePasswordToken(username,password, false,request.getRemoteAddr());  
            currentUser.login(token);


            Subject subject = SecurityUtils.getSubject();
            String sessionId = (String) subject.getSession().getId();

            /*//无Redis服务器,临时性解决token
            String Json = new Gson().toJson(token);
            byte[] encodeBase64 = Base64.encodeBase64(Json.getBytes("UTF-8"));
            String  base64 = new String(encodeBase64);//Base64值*/
            ActiveUser activeUser = ShiroUtil.getActiveUser();
            return ResultSuperApp.getSuccess(activeUser, "登录成功", 200, sessionId);
            //SecurityUtils.getSubject().getSession().setTimeout(-1000l);
        } catch (Exception e) {
            //根据与异常信息抛出对应的异常
            if(e.getClass().getName()!=null){
                if(UnknownAccountException.class.getName().equals(e.getClass().getName())){
                    //抛出账号不存在异常
                    error="账号不存在";
                    }else    if(IncorrectCredentialsException.class.getName().equals(e.getClass().getName())){
                            //
                    //throw new CustomException("密码错误");
                    error = "用户名密码错误";
                }else{
                    //密码错误
                    //throw new CustomException("未知错误异常");
                    error = "未知错误异常";
                }
            }
            return ResultSuperApp.getFailureInstance(error, 499);
        }
    }

注意:以上代码注释掉的部分是返回登录的token信息,之后每次前端请求的时候,参数都需要带着这个token。
放开的代码片段是登录后,返回shiro的sessionid,前端在cookie里保存一下这个sessionid,每次请求的时候参数中都需要加上sessionid。
两种方式都可以使用,但是本人推荐返回sessionid 的方式,因为前端给了sessionid 之后,我们只需要在服务中通过sessionid 获取shiro的session信息,然后就能获取到shiro对应的用户信息。而使用token的这种方式的话,每次前端请求过来,后端都需要根据这个token再登录一下。两者的区别就在这里。

获取用户信息(根据sessionid)

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import org.springframework.beans.factory.annotation.Autowired;

import com.eaju.bos.dao.mapper.DownloadCenterMapper;
import com.eaju.bos.dao.mapper.SonUserMapper;
import com.eaju.bos.dao.mapper.SysUserMapper;
import com.eaju.bos.entity.SysUser;
import com.eaju.bos.vo.ActiveUser;
import com.eaju.bos.vo.UserCustom;

/**
 * 
 */
public class ShiroUtil {


    /**
     * 
     * 

description: 获取ActiveUser并保存至session中一份

* @return * @date 2016年8月15日 下午3:37:23 * @author MrDuan */
public static ActiveUser getActiveUser(){ //从shiro的session中取出activeUser Subject subject = SecurityUtils.getSubject(); //取出身份信息 ActiveUser activeUser = (ActiveUser) subject.getPrincipal(); if(activeUser!=null){ Session session = subject.getSession(); ActiveUser user = (ActiveUser) session.getAttribute("user"); if(user==null){ session.setAttribute("user", activeUser); } return activeUser; }else{ return null; } } /** * 根据sessionid 获取用户信息 * @param sessionID * @param request * @param response * @return */ public static ActiveUser getActiveUser(String sessionID,HttpServletRequest request,HttpServletResponse response) throws Exception{ boolean status = false; SessionKey key = new WebSessionKey(sessionID,request,response); Session se = SecurityUtils.getSecurityManager().getSession(key); Object obj = se.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); //org.apache.shiro.subject.SimplePrincipalCollection cannot be cast to com.hncxhd.bywl.entity.manual.UserInfo SimplePrincipalCollection coll = (SimplePrincipalCollection) obj; ActiveUser activeUser = (ActiveUser)coll.getPrimaryPrincipal(); if(activeUser!=null){ ActiveUser user = (ActiveUser) se.getAttribute("user"); if(user==null){ se.setAttribute("user", activeUser); } return activeUser; }else{ return null; } } }

sessionid 方式 Controller里获取用户信息

ActiveUser activeUser = null ;
        try {
            activeUser = ShiroUtil.getActiveUser(token, request, response);
        } catch (Exception e1) {
            if(UnknownSessionException.class.getName().equals(e1.getClass().getName())){
                //抛出用户获取失败异常
                retJsono.put("info", "用户获取失败!");
                retJsono.put("returnCode",1000);
                return retJsono;
            }else{
                retJsono.put("info", "内部错误!");
                retJsono.put("returnCode",500);
                return retJsono;
            }
        }

注意: 这里是举个例子,获取方式就是这个样子,ActiveUser 是你们自己存在shiro session里的用户实体,大家自己修改为自己的就可以了。

获取用户信息(token方式,每次请求过来都需要登录一下,不太推荐)

//登录获取用户信息
    private ActiveUser loginToken(HttpServletRequest request) {
        String token = request.getParameter("token");
        Subject currentUser = SecurityUtils.getSubject();
        byte[] decodeBase64 = Base64.decodeBase64(token);
        String stringtoken = new String(decodeBase64);//Base64值
        currentUser.login(new Gson().fromJson(stringtoken, UsernamePasswordToken.class));
        ActiveUser activeUser = ShiroUtil.getActiveUser();
        return activeUser;
    }

为什么这么做?
因为前后端分离后,前后端可能会部署在不同的服务器上面,会跨域,前端每次请求时,都会是一次新的请求,所以前端需要记住一个用户的标识,每次请求数据都传给后端。后端才能知道是哪个用户。

以上均为个人想法,大家有好的意见或者建议,我会修改。

你可能感兴趣的:(职场)