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 {


    /**
     * 
     * <p>description: 获取ActiveUser并保存至session中一份</p>
     * @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;
    }

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

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

  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值