springboot + jwt + shiro 前后端分离权限框架

权限类说明:

权限配置类:ShiroConfiguration (权限核心配置类)、AuthFilter(拦截器配置类)、AuthRealm(认证类)、AuthTokenVo、NoPermissionException(无权限异常处理类)、JWTUtil(token工具类)、AuthConstant(提示类)、ReturnMessage 返回信息类
测试需要的类:User UserController UserList UserPermission UserRole
maven坐标

权限核心配置

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @ClassName ShiroConfiguration
 * @Description
 * @Author XinChunYu
 * @Date 2020/5/29 13:42
 * @Version 1.0
 **/
@Configuration
public class ShiroConfiguration {

    private org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ShiroConfiguration.class);

    //从配置文件里面读取是否需要启动登录认证的开关,默认true
    //@Value("${jwt.auth}")
    private boolean auth = true;

    //配置拦截器
    @Bean
    public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //启用认证
        String openAuth = auth ? "auth" : "anon";

        //自定义过滤器链
        Map<String, javax.servlet.Filter> filters = new HashMap<>();
        //指定拦截器处理
        filters.put("auth", new com.lzqs.yuanzilian.shiro.AuthFilter());
        shiroFilterFactoryBean.setFilters(filters);
        Map<String, String> filterMap = new LinkedHashMap<>();

        //登录请求不拦截
        filterMap.put("/user/login", "anon");
        //登录页面需要用到的接口,不拦截
        filterMap.put("/user/fetchCurrentUser", "anon");
        //拦截所有接口请求,做权限判断
        filterMap.put("/**", openAuth);

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        logger.info("Shiro拦截器工厂类注入成功");
        return shiroFilterFactoryBean;
    }

    // SecurityManager 安全管理器;Shiro的核心
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        return securityManager;
    }

    //自定义身份认证realm
    @Bean
    public AuthRealm userRealm() {
        return new AuthRealm();
    }

    @Bean("lifecycleBeanPostProcessor")
    //管理shiro生命周期
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    //Shiro注解支持
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager((org.apache.shiro.mgt.SecurityManager) securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}

权限过滤器

package com.lzqs.yuanzilian.shiro;

import com.alibaba.fastjson.JSONObject;
import com.lzqs.yuanzilian.constant.ReturnMessage;
import com.lzqs.yuanzilian.shiro.util.AuthConstant;
import com.lzqs.yuanzilian.shiro.util.JWTUtil;
import io.micrometer.core.instrument.util.StringUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @ClassName AuthFilter
 * @Description 实现自定义的认证拦截器,接收传过来的token,实现前后端分离的权限认证
 * @Author XinChunYu
 * @Date 2020/5/29 14:03
 * @Version 1.0
 **/
public class AuthFilter extends AuthenticatingFilter {

    private org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(AuthorizingRealm.class);
    private ReturnMessage responseResult = ReturnMessage.failWithMsg(AuthConstant.AUTHENTICATE_FAIL);

        @Override
        protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
            return null;
        }

        /**
         * 在这里拦截所有请求
         * @param request
         * @param response
         * @param mappedValue
         * @return
         */
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
            String token = JWTUtil.getRequestToken((HttpServletRequest)request);
            if (!StringUtils.isBlank(token)){
                try {
                    this.executeLogin(request, response);
                } catch (Exception e) {
                    // 应用异常
                    logger.info(e.getMessage());
                    responseResult = ReturnMessage.failWithMsg(e.getMessage());
                    return false;
                }
            } else {
                // cookie中未检查到token或token为空
                HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
                String httpMethod = httpServletRequest.getMethod();
                String requestURI = httpServletRequest.getRequestURI();
                responseResult = ReturnMessage.failWithMsg(AuthConstant.TOKEN_BLANK);
                logger.info("请求 {} 的Token为空 请求类型 {}", requestURI, httpMethod);
                return false;
            }
            return true;
        }

        /**
         * 请求失败拦截,请求终止,不进行转发直接返回客户端拦截结果
         * @param request
         * @param response
         * @return
         * @throws Exception
         */
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception{
            HttpServletResponse httpServletResponse = (HttpServletResponse)response;
            httpServletResponse.setContentType("application/json; charset=utf-8");
            httpServletResponse.setCharacterEncoding("UTF-8");
            //ReturnMessage returnMessage = ReturnMessage.failWithMsg(AuthConstant.AUTHENTICATE_FAIL);
            httpServletResponse.getWriter().print(JSONObject.toJSONString(responseResult));
            return false;
        }

        /**
         * 用户存在,执行登录认证
         * @param request
         * @param response
         * @return
         * @throws Exception
         */
        @Override
        protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
            String token = JWTUtil.getRequestToken((HttpServletRequest)request);
            AuthTokenVo jwtToken = new AuthTokenVo(token);
            // 提交给AuthRealm进行登录认证
            getSubject(request, response).login(jwtToken);
            return true;
        }
}

token认证和权限认证

import com.lzqs.yuanzilian.shiro.controller.User;
import com.lzqs.yuanzilian.shiro.controller.UserList;
import com.lzqs.yuanzilian.shiro.controller.UserPermission;
import com.lzqs.yuanzilian.shiro.controller.UserRole;
import com.lzqs.yuanzilian.shiro.util.AuthConstant;
import io.micrometer.core.instrument.util.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * @ClassName AuthRealm
 * @Description
 * @Author XinChunYu
 * @Date 2020/5/29 13:51
 * @Version 1.0
 **/
public class AuthRealm extends AuthorizingRealm {

    private org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(AuthorizingRealm.class);

    /**
     * 重写,绕过身份令牌异常导致的shiro报错
     * @param authenticationToken
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken authenticationToken){
        return authenticationToken instanceof AuthTokenVo;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        logger.info("用户角色权限认证");
        //获取用户登录信息
        User user = (User)principals.getPrimaryPrincipal();
        //添加角色和权限
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        for(UserRole userRole : user.getUserRoleList()){
            authorizationInfo.addRole(userRole.getUserRoleName());
            for(UserPermission permissionVo : userRole.getUserPermissionList()){
                authorizationInfo.addStringPermission(permissionVo.getUserPermissionName());
            }
        }
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("执行认证逻辑");
        //获得token
        String token = (String)authenticationToken.getCredentials();
        //获得token中的用户信息
        String username = JwtAuthenticator.getUsername(token);
        //判空
        if(StringUtils.isBlank(username)){
            throw new AuthenticationException(AuthConstant.TOKEN_BLANK);
        }
        User user = null;
        try{
            for(User u : UserList.userList){
                if(u.getUsername().equals(username)){
                    user = u;
                }
            }
            //查询用户是否存在
            if(user == null){
                throw new AuthenticationException(AuthConstant.TOKEN_INVALID);
                //token过期
            }else if(!(JwtAuthenticator.verifyToken(token, username, user.getPassword()))){
                throw new AuthenticationException(AuthConstant.TOKEN_EXPIRE);
            }
        }catch (Exception e){
            throw e;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user,
                token,
                getName());
        return authenticationInfo;
    }
}

jwt token对象

import org.apache.shiro.authc.AuthenticationToken;

/**
 * @ClassName AuthTokenVo
 * @Description
 * @Author XinChunYu
 * @Date 2020/5/29 14:09
 * @Version 1.0
 **/
public class AuthTokenVo implements AuthenticationToken {
    private String token;
    public AuthTokenVo(String token){
        this.token = token;
    }

    @Override
    public Object getPrincipal(){
        return token;
    }

    @Override
    public Object getCredentials(){
        return token;
    }
}

异常处理

import com.alibaba.fastjson.JSONObject;
import com.lzqs.yuanzilian.constant.ReturnMessage;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @ClassName NoPermissionException
 * @Description
 * @Author XinChunYu
 * @Date 2020/5/30 15:12
 * @Version 1.0
 **/
@ControllerAdvice
public class NoPermissionException {

    /**
     * 用户角色权限认证 当没有权限时会报UnauthorizedException异常 此处处理异常给前端返回提示语
     * @param response
     * @param ex
     * @throws IOException
     */
    @ResponseBody
    @ExceptionHandler(UnauthorizedException.class)
    public void handleShiroException(HttpServletResponse response, Exception ex) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse)response;
        httpServletResponse.setContentType("application/json; charset=utf-8");
        httpServletResponse.setCharacterEncoding("UTF-8");
        //ReturnMessage returnMessage = ReturnMessage.failWithMsg(AuthConstant.AUTHENTICATE_FAIL);
        httpServletResponse.getWriter().print(JSONObject.toJSONString(ReturnMessage.failWithMsg("访问了无权限目录")));
    }
   //执行认证逻辑认证不通过时会走  过滤器AuthFilter中的onAccessDenied方法 所以这个异常不捕获
   /* @ResponseBody
    @ExceptionHandler(AuthorizationException.class)
    public String AuthorizationException(Exception ex) {
        return "权限认证失败";
    }*/
}

jwt token工具类

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.Date;

/**
 * @ClassName JWTUtil
 * @Description
 * @Author XinChunYu
 * @Date 2020/5/29 13:18
 * @Version 1.0
 **/
public class JWTUtil {

    // 过期时间50分钟
    private static final long EXPIRE_TIME = 50*60*1000;

    /**
     * 校验token是否正确
     * @param token 密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username", username)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名,5min后过期
     * @param username 用户名
     * @param secret 用户的密码
     * @return 加密的token
     */
    public static String sign(String username, String secret) {
        try {
            Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            return JWT.create()
                    .withClaim("username", username)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    public static String getRequestToken(HttpServletRequest request) {
        return request.getHeader("token");
    }
}

认证提示

package com.lzqs.yuanzilian.shiro.util;

/**
 * @ClassName AuthConstant
 * @Description 权限相关的常量
 * @Author XinChunYu
 * @Date 2020/5/29 14:06
 * @Version 1.0
 **/
public class AuthConstant {

        /**
         * cookie中存储的token字段名
         */
        public final static String COOKIE_TOKEN_NAME = "Authorization";

        /**
         * token有效时间 时*分*秒*1000L
         */
        public final static Long EXPIRE_TIME = 3*60*1000L;//先设置3分钟

        //登录认证结果,返回给前端
        public final static String UNKNOWN_ACCOUNT = "登录失败, 用户不存在。";

        public final static String WRONG_PASSWORD = "登录失败,密码错误。";

        public final static String TOKEN_BLANK = "验证失败,token为空,请登录。";

        public final static String TOKEN_INVALID = "验证失败,token错误。";

        public final static String TOKEN_EXPIRE = "验证失败,token过期,请重新登录。";

        public final static String AUTHENTICATE_FAIL = "无访问权限,请尝试登录或联系管理员。";
}

ReturnMessage返回提示类

package com.lzqs.yuanzilian.constant;

import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 通用的返回类
 **/
public class ReturnMessage implements Serializable {
    //状态码 100-成功,200-失败 400-带信息失败
    private int code;
    //提示信息
    private String msg;
    //用户要返回给浏览器的数据
    private Map<String, Object> data = new LinkedHashMap<>();

    public static ReturnMessage successWithData(Map<String, Object> data) {
        ReturnMessage result = new ReturnMessage();
        result.setCode(100);
        result.setMsg("成功");
        result.setData(data);
        return result;
    }

    public static ReturnMessage success() {
        ReturnMessage result = new ReturnMessage();
        result.setCode(100);
        result.setMsg("成功");
        return result;
    }

    public static ReturnMessage successWithMsg(String newmsg){
        ReturnMessage result = new ReturnMessage();
        result.setCode(100);
        result.setMsg(newmsg);
        return result;
    }

    public static ReturnMessage fail() {
        ReturnMessage result = new ReturnMessage();
        result.setCode(200);
        result.setMsg("系统错误");
        return result;
    }

    public static ReturnMessage failWithMsg(String newmsg) {
        ReturnMessage result = new ReturnMessage();
        result.setCode(400);
        result.setMsg(newmsg);
        return result;
    }


    /**
     * 失败 + 自定义msg,缺省为"处理失败"
     *
     * @param newmsg
     * @return
     */
    public static ReturnMessage failWithMsg(int code, String newmsg) {
        ReturnMessage result = new ReturnMessage();
        result.setCode(code);
        if (StringUtils.isEmpty(newmsg)) {
            newmsg = "处理失败";
        }
        result.setMsg(newmsg);
        return result;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Map<String, Object> getData() {
        return data;
    }

    public void setData(Map<String, Object> data) {
        this.data = data;
    }

    public ReturnMessage add(String key, Object value) {
        this.getData().put(key, value);
        return this;
    }
}

controller控制器

import com.lzqs.yuanzilian.constant.ReturnMessage;
import com.lzqs.yuanzilian.shiro.util.AuthConstant;
import com.lzqs.yuanzilian.shiro.util.JWTUtil;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;

/**
 * @ClassName UserController
 * @Description
 * @Author XinChunYu
 * @Date 2020/5/29 14:15
 * @Version 1.0
 **/
@Controller
@RequestMapping("/user")
public class UserController {


    @RequestMapping("/login")
    @ResponseBody
    public ReturnMessage login(@RequestBody Map<String, Object> map){
        String username = map.get("username").toString();
        String password = map.get("password").toString();
        User user = null;
        for(User u : UserList.userList){
            if(u.getUsername().equals(username)){
                user = u;
            }
        }
        if(user == null){
            //账号不存在
            return ReturnMessage.failWithMsg(AuthConstant.UNKNOWN_ACCOUNT);
        }else if(!user.getPassword().equals(password)){
            //密码错误
            return ReturnMessage.failWithMsg(AuthConstant.WRONG_PASSWORD);
        }else{
            //通过认证, 生成签名
            String token = JWTUtil.sign(user.getUsername(), user.getPassword());
            return ReturnMessage.success().add("token", token);
        }
    }


    @RequiresPermissions("shop")
    @RequestMapping("/shop")
    @ResponseBody
    public ReturnMessage shop(@RequestBody Map<String, Object> map){

            return ReturnMessage.success();
    }

    @RequiresPermissions("order")
    @RequestMapping("/order")
    @ResponseBody
    public ReturnMessage order(@RequestBody Map<String, Object> map){

        return ReturnMessage.success();
    }

    /**
     * 不加@RequiresPermissions 注解时不会进行用户授权认证
     * @param map
     * @return
     */
    @RequestMapping("/game")
    @ResponseBody
    public ReturnMessage game(@RequestBody Map<String, Object> map){
        return ReturnMessage.success();
    }

    @RequestMapping("/address")
    @ResponseBody
    public ReturnMessage address(@RequestBody Map<String, Object> map){
        return ReturnMessage.success();
    }
}

用户类

package com.lzqs.yuanzilian.shiro.controller;

import java.util.List;

/**
 * @ClassName UserBean
 * @Description 用户表
 * @Author XinChunYu
 * @Date 2020/5/29 13:16
 * @Version 1.0
 **/
public class User {
    private Long userId;
    private String username;
    private String password;
    private String salt;//盐值
    private List<UserRole> userRoleList;

    public User() {
    }

    public User(Long userId, String username, String password, String salt, List<UserRole> userRoleList) {
        this.userId = userId;
        this.username = username;
        this.password = password;
        this.salt = salt;
        this.userRoleList = userRoleList;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<UserRole> getUserRoleList() {
        return userRoleList;
    }

    public void setUserRoleList(List<UserRole> userRoleList) {
        this.userRoleList = userRoleList;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }
}

角色类

package com.lzqs.yuanzilian.shiro.controller;

import java.util.List;

/**
 * @ClassName UserRole
 * @Description 角色表
 * @Author XinChunYu
 * @Date 2020/5/29 13:34
 * @Version 1.0
 **/
public class UserRole {
    private Long userRoleId;
    private String userRoleName;
    List<UserPermission> userPermissionList;

    public UserRole(Long userRoleId, String userRoleName, List userPermissionList) {
        this.userRoleId = userRoleId;
        this.userRoleName = userRoleName;
        this.userPermissionList = userPermissionList;
    }

    public Long getUserRoleId() {
        return userRoleId;
    }

    public void setUserRoleId(Long userRoleId) {
        this.userRoleId = userRoleId;
    }

    public String getUserRoleName() {
        return userRoleName;
    }

    public void setUserRoleName(String userRoleName) {
        this.userRoleName = userRoleName;
    }

    public List<UserPermission> getUserPermissionList() {
        return userPermissionList;
    }

    public void setUserPermissionList(List<UserPermission> userPermissionList) {
        this.userPermissionList = userPermissionList;
    }
}

权限

package com.lzqs.yuanzilian.shiro.controller;

/**
 * @ClassName Permission
 * @Description 权限表
 * @Author XinChunYu
 * @Date 2020/5/29 13:35
 * @Version 1.0
 **/
public class UserPermission {
    private Long userPermissionId;
    private String userPermissionName;

    public UserPermission(Long userPermissionId, String userPermissionName) {
        this.userPermissionId = userPermissionId;
        this.userPermissionName = userPermissionName;
    }

    public Long getUserPermissionId() {
        return userPermissionId;
    }

    public void setUserPermissionId(Long userPermissionId) {
        this.userPermissionId = userPermissionId;
    }

    public String getUserPermissionName() {
        return userPermissionName;
    }

    public void setUserPermissionName(String userPermissionName) {
        this.userPermissionName = userPermissionName;
    }
}

用户集合在这就不建表查数据库了

package com.lzqs.yuanzilian.shiro.controller;

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

/**
 * @ClassName UserList
 * @Description
 * @Author XinChunYu
 * @Date 2020/5/29 16:15
 * @Version 1.0
 **/
public class UserList {

    public static List<User> userList = new ArrayList<>();
    static{
        ArrayList<UserPermission> userPermissionArrayList1 = new ArrayList<>();
        userPermissionArrayList1.add(new UserPermission(1l,"shop"));
        userPermissionArrayList1.add(new UserPermission(2l,"game"));
        userPermissionArrayList1.add(new UserPermission(1l,"order"));
        userPermissionArrayList1.add(new UserPermission(1l,"address"));
        ArrayList<UserRole> userRoleArrayList1 = new ArrayList<>();
        userRoleArrayList1.add(new UserRole(1L, "老板", userPermissionArrayList1));
        User user1 = new User(1l, "admin", "123456", "iwejfiwjf", userRoleArrayList1);

        ArrayList<UserPermission> userPermissionArrayList2 = new ArrayList<>();
        userPermissionArrayList2.add(new UserPermission(1l,"shop"));
        userPermissionArrayList2.add(new UserPermission(2l,"game"));
        ArrayList<UserRole> userRoleArrayList2 = new ArrayList<>();
        userRoleArrayList2.add(new UserRole(2L, "经理", userPermissionArrayList2));
        User user2 = new User(2l, "xiaoming", "123456", "jfiosjfos", userRoleArrayList2);

        userList.add(user1);
        userList.add(user2);
    }
}

maven坐标

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.7.0</version>
        </dependency>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342