shiro Front-End Separation Framework User Login Solution
Published: 2019-05-27

Introduction

Recently, the company changed a project originally controlled by springmvc+shiro's permission to separate the front end from the back end so that front-end personnel can have more time to do front-end interactive work and improve user experience.

But this problem comes. Without separation, shiro's permission was logged in through credentials. Now it needs to be changed to submit login information for front-end ajax to log in, so shiro's login method has been changed. Here is a record.

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

Note: The part commented out by the above code is to return the login token information. After that, every time the front end requests, the parameter needs to carry this token.
The released code fragment is to return shiro's sessionid after logging in. The front end saves this sessionid in cookie inside. The sessionid needs to be added to the parameters during each request.
Both methods can be used, but I recommend the method of returning sessionid, because after the front end gives sessionid, we only need to obtain shiro's session information through sessionid in the service, and then we can obtain shiro's corresponding user information.However, in this way of using token, every time the front end requests to come over, the back end needs to log in again according to the token.This is the difference between the two.

get user information (according to 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 mode Controller inside obtains user information

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

Note: Here is an example. This is how it is obtained. ActiveUser is your own user entity that exists in shiro session inside. You can modify it to your own.

Get user information (token method, login is required every time a request comes in, not recommended)

//登录获取用户信息
    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;
    }

Why did you do this?
Because after the front and rear ends are separated, the front and rear ends may be deployed on different servers and will cross domains. Each request from the front end will be a new request. Therefore, the front end needs to remember a user's identification, and each request data will be transmitted to the back end.The backend can only know which user it is.

The above are all personal thoughts. If you have good opinions or suggestions, I will revise them.