shiro权限控制

shiro权限控制

书接上文(如有逻辑问题请看上文转载内容)

配置类

ShiroConfig

import com.youotech.login.dao.UserDao;
import com.youotech.login.entity.Permission;
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 org.apache.shiro.mgt.SecurityManager;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**

  • Created by EalenXie on 2019/3/25 15:12.
    */
    @Configuration
    public class ShiroConfig {

    @Resource
    private UserDao permissionRepository;

    @Resource
    private UserRealm userRealm;

    /**

    • 配置 资源访问策略 . web应用程序 shiro核心过滤器配置
      */
      @Bean
      public ShiroFilterFactoryBean factoryBean(SecurityManager securityManager) {
      ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
      factoryBean.setSecurityManager(securityManager);
      //加上放开option配置
      Map<String, Filter> filters = factoryBean.getFilters();
      // 注意这里不要用Bean的方式,否则会报错
      filters.put(“authc”, new ShiroUserFilter());
      factoryBean.setFilters(filters);
      //控制登录
      factoryBean.setLoginUrl("/login");//登录页
      factoryBean.setSuccessUrl("/index");//首页
      factoryBean.setUnauthorizedUrl("/unauthorized");//未授权界面;
      factoryBean.setFilterChainDefinitionMap(setFilterChainDefinitionMap()); //配置 拦截过滤器链
      return factoryBean;
      }

    /**

    • 配置 SecurityManager,可配置一个或多个realm
      */
      @Bean
      public SecurityManager securityManager() {
      DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
      securityManager.setRealm(userRealm);
      // securityManager.setRealm(xxxxRealm);
      return securityManager;
      }

    /**

    • 开启shiro 注解支持. 使以下注解能够生效 :
    • 需要认证 {@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}
    • 需要用户 {@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}
    • 需要访客 {@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}
    • 需要角色 {@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles}
    • 需要权限 {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions}
      */
      @Bean
      public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
      AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
      authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
      return authorizationAttributeSourceAdvisor;
      }

    /**

    • 配置 拦截过滤器链. map的键 : 资源地址 ; map的值 : 所有默认Shiro过滤器实例名
    • 默认Shiro过滤器实例 参考 : {@link org.apache.shiro.web.filter.mgt.DefaultFilter}
      */
      private Map<String, String> setFilterChainDefinitionMap() {
      Map<String, String> filterMap = new LinkedHashMap<>();
      //注册 数据库中所有的权限 及其对应url
      List allPermission = permissionRepository.selectPrmission();//数据库中查询所有权限
      for (Permission p : allPermission) {
      filterMap.put(p.getUrl(), “perms[” + p.getName() + “]”); //拦截器中注册所有的权限
      }
      filterMap.put("/static/", “anon”); //公开访问的资源
      filterMap.put("/sys/
      ", “anon”); //公开接口地址
      filterMap.put("/logout", “logout”); //配置登出页,shiro已经帮我们实现了跳转
      filterMap.put("/**", “authc”); //所有资源都需要经过验证
      return filterMap;
      }
      }

ShiroSessionUtils

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

public class ShiroSessionUtils {

public static void setAttribute(Object key, Object value) {
	Subject account = SecurityUtils.getSubject();
	if (null != account) {
		Session session = account.getSession();
		if (null != session) {
			session.setAttribute(key, value);
			session.setTimeout(28800000);//8个小时
		}
	}
}

public static Object getAttribute(Object key) {
	Subject account = SecurityUtils.getSubject();
	if (null != account) {
		Session session = account.getSession();
		if (null != session) {
			return session.getAttribute(key);
		}
	}
	return null;
}

public static Object removeAttribute(Object key) {
	Subject account = SecurityUtils.getSubject();
	if (null != account) {
		Session session = account.getSession();
		if (null != session) {
			return session.removeAttribute(key);
		}
	}
	return null;
}

}

ShiroUserFilter

import org.apache.shiro.web.filter.authc.UserFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**

  • 重写shiro的UserFilter,实现通过OPTIONS请求

  • @author MDY
    */
    public class ShiroUserFilter extends UserFilter {

    /**

    • 在访问过来的时候检测是否为OPTIONS请求,如果是就直接返回true
      */
      @Override
      protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
      HttpServletResponse httpResponse = (HttpServletResponse) response;
      HttpServletRequest httpRequest = (HttpServletRequest) request;
      if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
      setHeader(httpRequest,httpResponse);
      return true;
      }

      return super.preHandle(request,response);
      }

    /**

    • 该方法会在验证失败后调用,这里由于是前后端分离,后台不控制页面跳转
    • 因此重写改成传输JSON数据
      */
      @Override
      protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
      saveRequest(request);
      setHeader((HttpServletRequest) request,(HttpServletResponse) response);
      PrintWriter out = response.getWriter();
      //自己控制返回的json数据
      //out.println(new Result(ResultStatusCode.SHIRO_ERROR));
      out.flush();
      out.close();
      }

    /**

    • 为response设置header,实现跨域
      */
      private void setHeader(HttpServletRequest request, HttpServletResponse response){
      //跨域的header设置
      response.setHeader(“Access-control-Allow-Origin”, request.getHeader(“Origin”));
      response.setHeader(“Access-Control-Allow-Methods”, request.getMethod());
      response.setHeader(“Access-Control-Allow-Credentials”, “true”);
      response.setHeader(“Access-Control-Allow-Headers”, request.getHeader(“Access-Control-Request-Headers”));
      //防止乱码,适用于传输JSON数据
      response.setHeader(“Content-Type”,“application/json;charset=UTF-8”);
      response.setStatus(HttpStatus.OK.value());
      }
      }

ShiroUtils

import com.youotech.login.entity.SysUserEntity;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

/**

  • Shiro工具类
    */
    public class ShiroUtils {

    /** 加密算法 /
    public final static String hashAlgorithmName = “SHA-256”;
    /
    * 循环次数 */
    public final static int hashIterations = 16;

    public static String sha256(String password, String salt) {
    return new SimpleHash(hashAlgorithmName, password, salt, hashIterations).toString();
    }

    public static Session getSession() {
    return SecurityUtils.getSubject().getSession();
    }

    public static Subject getSubject() {
    return SecurityUtils.getSubject();
    }

    public static SysUserEntity getUserEntity() {
    return (SysUserEntity)SecurityUtils.getSubject().getPrincipal();
    }

    public static Integer getUserId() {
    return getUserEntity().getId();
    }

    public static void setSessionAttribute(Object key, Object value) {
    getSession().setAttribute(key, value);
    }

    public static Object getSessionAttribute(Object key) {
    return getSession().getAttribute(key);
    }

    public static boolean isLogin() {
    return SecurityUtils.getSubject().getPrincipal() != null;
    }

    public static void logout() {
    SecurityUtils.getSubject().logout();
    }
    }

UserRealm

import com.youotech.login.dao.UserDao;
import com.youotech.login.entity.Permission;
import com.youotech.login.entity.RoleModel;
import com.youotech.login.entity.SysUserEntity;
import org.apache.shiro.authc.*;
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.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

@Component
public class UserRealm extends AuthorizingRealm {

@Resource
private UserDao userRepository;

/**
 * 权限核心配置 根据数据库中的该用户 角色 和 权限
 */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    SysUserEntity user = (SysUserEntity) principals.getPrimaryPrincipal();
    //根据用户id获取角色列表
    List<RoleModel> roles = userRepository.selectRoleByUserId(user.getId());
    if(roles!=null && roles.size()>0){
        for (RoleModel role : roles) {
            authorizationInfo.addRole(role.getName());
            //根据角色id获取权限列表
            List<Permission> permissions=userRepository.selectPrmissionById(role.getId());
            if(permissions!=null && permissions.size()>0){
                for (Permission permission : permissions) {
                    authorizationInfo.addStringPermission(permission.getName());
                }
            }
        }
    }
    return authorizationInfo;
}

/**
 * 用户登陆 凭证信息
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
    UsernamePasswordToken token = (UsernamePasswordToken)authcToken;

    //查询用户信息
    SysUserEntity user = new SysUserEntity();
    user.setLoginName(token.getUsername());
    user = userRepository.selectByName(user.getLoginName());

    //把user放到session
    if(user!=null){
        ShiroSessionUtils.setAttribute("loginUser",user);
    }

    //账号不存在
    if(user == null) {
        throw new UnknownAccountException("账号或密码不正确");
    }


    //账号锁定
    if(user.getState() == 0){
        throw new LockedAccountException("账号已被锁定,请联系管理员");
    }

    System.out.println(getName()+"qqqqqqqqqqqq");
    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPwd(),getName());
    //清除之前的授权信息
    super.clearCachedAuthorizationInfo(info.getPrincipals());
    return info;
 }
}

登录模块login

controller

import com.youotech.common.Result;
import com.youotech.common.VerifyCode;
import com.youotech.login.entity.SysUserEntity;
import com.youotech.login.service.LoginService;
import com.youotech.shiro.ShiroSessionUtils;
import com.youotech.shiro.ShiroUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

/**

  • 登录相关

/
@Controller
@CrossOrigin(allowCredentials = “true”, allowedHeaders = "
")
public class SysLoginController {
@Autowired
private LoginService loginService;

/**
 * 登录
 */
@ResponseBody
@RequestMapping(value = "/sys/login", method = RequestMethod.GET)
public Result login(String loginName, String pwd,String verifyCode) {
	try {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if (requestAttributes == null) {
			return new Result(false,500,"requestAttributes==null");
		}
		HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
		if (request == null) {
			return new Result(false,500,"requestAttributes==null");
		}
		Object code = request.getSession().getAttribute("verifyCode");
		if (code == null) {
			return new Result(false,500,"验证码已过期");
		}
		if (!code.toString().toLowerCase().equals(verifyCode)) {
			return new Result(false,500,"验证码错误");
		}
		Subject subject = ShiroUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(loginName,
				pwd);
		subject.login(token);

	} catch (UnknownAccountException e) {
		return new Result(false, 500, e.getMessage());
	}  catch (LockedAccountException e) {
		return new Result(false, 500, "账号已被锁定,请联系管理员");
	}
	SysUserEntity user  = null;
	try {
		user = (SysUserEntity) ShiroSessionUtils.getAttribute("loginUser");
	} catch (Exception e) {
		e.printStackTrace();
	}
	System.out.println("SysUserEntity===>"+user.getLoginName()+"=="+user.getPwd());
	return new Result(true,200,"success");
}

/**
 * 退出
 */
@RequestMapping(value = "/sys/logout", method = RequestMethod.GET)
public String logout() {
	ShiroUtils.logout();
	return "login";
}

/**
 * 获取当前登录用户信息
 */
@RequestMapping(value = "/sys/getLoginUserInfo", method = RequestMethod.GET)
@ResponseBody
public SysUserEntity getLoginUserInfo() {
	try {
		SysUserEntity user = ShiroUtils.getUserEntity();
		return user;
	} catch (Exception e) {
	}
	return null;
}


/**
 * 获取菜单栏
 *
 * @return
 */
@RequestMapping("getMenuData")
@ResponseBody
public Result getMenuData() {
	List<String> urlList = loginService.getData();
	return new Result(false,200,"返回权限信息成功",urlList);
}

/**
 * 获取验证码
 * @param response
 * @param request
 */
@ResponseBody
@RequestMapping(value = "/sys/getVerifyCode", method = RequestMethod.GET)
@CrossOrigin(allowCredentials = "true")
public void getVerificationCode(HttpServletResponse response, HttpServletRequest request) {

	try {

		int width = 300;

		int height = 69;

		BufferedImage verifyImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

//生成对应宽高的初始图片

		String randomText = VerifyCode.drawRandomText(width, height, verifyImg);

//单独的一个类方法,出于代码复用考虑,进行了封装。

//功能是生成验证码字符并加上噪点,干扰线,返回值为验证码字符

		request.getSession().setAttribute("verifyCode", randomText);

		response.setContentType("image/png");//必须设置响应内容类型为图片,否则前台不识别

		OutputStream os = response.getOutputStream(); //获取文件输出流

		ImageIO.write(verifyImg, "png", os);//输出图片流

		os.flush();

		os.close();//关闭流

	} catch (IOException e) {

		e.printStackTrace();

	}
 }
}

dao

import com.youotech.login.entity.Permission;
import com.youotech.login.entity.RoleModel;
import com.youotech.login.entity.SysUserEntity;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserDao {
/**
* [新增]
* @author itdaoyang
* @date 2020/03/03
**/
int insert(SysUserEntity sysUserEntity);

/**
 * [刪除]
 * @author itdaoyang
 * @date 2020/03/03
 **/
int delete(int id);

/**
 * [更新]
 * @author itdaoyang
 * @date 2020/03/03
 **/
int update(SysUserEntity sysUserEntity);

/**
 * [查询] 根据主键 id 查询
 * @author itdaoyang
 * @date 2020/03/03
 **/
SysUserEntity selectByName(String loginNmae);

/**
 * [查询] 分页查询
 * @author itdaoyang
 * @date 2020/03/03
 **/
List<SysUserEntity> pageList(int offset, int pagesize);

/**
 * [查询] 分页查询 count
 * @author itdaoyang
 * @date 2020/03/03
 **/
int pageListCount(int offset,int pagesize);

List<RoleModel> selectRoleByUserId(Integer id);

List<Permission> selectPrmissionById(Integer roleId);

List<Permission> selectPrmission();}

entity

权限

import lombok.Data;

import javax.persistence.Column;
import java.io.Serializable;
import java.util.Date;

/**

  • permission

  • @author 大狼狗 2020-03-03
    */
    @Data
    public class Permission implements Serializable {

    private static final long serialVersionUID = 1L;

    /**

    • id
      */
      private Integer id;

    /**

    • url
      */
      @Column(unique = true)
      private String url;

    /**

    • 名称
      */
      @Column(unique = true)
      private String name;

    /**

    • 创建人
      */
      private String createUser;

    /**

    • 创建时间
      */
      private Date createDate;

}

角色

import java.io.Serializable;
import lombok.Data;

import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import java.util.Date;
import java.util.List;

/**

  • role_model

  • @author 大狼狗 2020-03-03
    */
    @Data
    public class RoleModel implements Serializable {

    private static final long serialVersionUID = 1L;

    /**

    • 主键id
      */
      private Integer id;

    /**

    • 类型
      */
      private Integer type;

    /**

    • 名称
      */
      @Column(unique = true)
      private String name;

    /**

    • 36
      */
      private String createUser;

    /**

    • 创建时间
      */
      private Date createDate;

    @ManyToMany(fetch= FetchType.EAGER)
    private List permissions;
    }

用户

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**

  • sys_user_entity

  • @author itdaoyang 2020-03-02
    */
    @Data
    public class SysUserEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    /**

    • 主键id
      */
      private Integer id;

    /**

    • 真实姓名
      */
      private String userTrueName;

    /**

    • 登录名
      */
      @Column(unique = true)
      private String loginName;

    /**

    • 登录密码
      */
      private String pwd;

    /**

    • 状态(0:正常,1锁定)
      */
      private Integer state;

    /**

    • 错误次数
      */
      private Integer errorCount;

    /**

    • 创建人
      */
      private String createUser;

    /**

    • 创建时间
      */
      private Date createDate;

    /**

    • 最后登录时间
      */
      private Date astLoginTime;

    @ManyToMany(fetch= FetchType.EAGER)
    private List roleModels;

}

xml

<?xml version="1.0" encoding="UTF-8"?>
<resultMap id="BaseResultMap" type="com.youotech.login.entity.SysUserEntity">
    <result column="id" property="id"/>
    <result column="user_true_name" property="userTrueName"/>
    <result column="login_name" property="loginName"/>
    <result column="pwd" property="pwd"/>
    <result column="state" property="state"/>
    <result column="error_count" property="errorCount"/>
    <result column="create_user" property="createUser"/>
    <result column="create_date" property="createDate"/>
    <result column="ast_login_time" property="astLoginTime"/>
</resultMap>

<sql id="Base_Column_List">
    id,
    user_true_name,
    login_name,
    pwd,
    state,
    error_count,
    create_user,
    create_date,
    ast_login_time
</sql>

<insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id"
        parameterType="com.youotech.login.entity.SysUserEntity">
    INSERT INTO u_user
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test='null != userTrueName'>
            user_true_name,
        </if>
        <if test='null != loginName'>
            login_name,
        </if>
        <if test='null != pwd'>
            pwd,
        </if>
        <if test='null != state'>
            state,
        </if>
        <if test='null != errorCount'>
            error_count,
        </if>
        <if test='null != createUser'>
            create_user,
        </if>
        <if test='null != createDate'>
            create_date,
        </if>
        <if test='null != astLoginTime'>
            ast_login_time
        </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
        <if test='null != userTrueName'>
            #{userTrueName},
        </if>
        <if test='null != loginName'>
            #{loginName},
        </if>
        <if test='null != pwd'>
            #{pwd},
        </if>
        <if test='null != state'>
            #{state},
        </if>
        <if test='null != errorCount'>
            #{errorCount},
        </if>
        <if test='null != createUser'>
            #{createUser},
        </if>
        <if test='null != createDate'>
            #{createDate},
        </if>
        <if test='null != astLoginTime'>
            #{astLoginTime}
        </if>
    </trim>
</insert>

<delete id="delete">
    DELETE FROM u_user
    WHERE id = #{id}
</delete>

<update id="update" parameterType="com.youotech.login.entity.SysUserEntity">
    UPDATE u_user
    <set>
        <if test='null != userTrueName'>user_true_name = #{userTrueName},</if>
        <if test='null != loginName'>login_name = #{loginName},</if>
        <if test='null != pwd'>pwd = #{pwd},</if>
        <if test='null != state'>state = #{state},</if>
        <if test='null != errorCount'>error_count = #{errorCount},</if>
        <if test='null != createUser'>create_user = #{createUser},</if>
        <if test='null != createDate'>create_date = #{createDate},</if>
        <if test='null != astLoginTime'>ast_login_time = #{astLoginTime}</if>
    </set>
    WHERE id = #{id}
</update>


<select id="selectByName" resultType="com.youotech.login.entity.SysUserEntity">
    SELECT
    *
    FROM u_user
    WHERE login_name = #{loginName}
</select>

<select id="pageList" resultMap="BaseResultMap">
    SELECT
    <include refid="Base_Column_List"/>
    FROM u_user
    LIMIT #{offset}, #{pageSize}
</select>

<select id="pageListCount" resultType="java.lang.Integer">
    SELECT count(1)
    FROM u_user
</select>

<select id="selectRoleByUserId" resultType="com.youotech.login.entity.RoleModel">
  SELECT r.*  FROM u_user_role ur ,u_user u,u_role r WHERE  u.id=ur.uid and r.id=ur.rid and u.id=#{id}
</select>

<select id="selectPrmissionById" resultType="com.youotech.login.entity.Permission">
   SELECT p.*  FROM u_permission p ,u_role_permission rp,u_role r WHERE  p.id=rp.pid and r.id=rp.rid and r.id=#{roleId}
</select>
<select id="selectPrmission" resultType="com.youotech.login.entity.Permission">
    SELECT * from u_permission
</select>

为什么没有service因为根本用不到

关于注册的注解使用

1.访问/sys/getVerifyCode获取验证码
2.登录
3.调接口
4.不通是不是?不通就对了,看controller层上面注解

@RequiresRoles(“administrator”):控制角色,有此角色的用户才能访问该接口
@RequiresPermissions(“add”):控制权限,有此权限的用户才能访问该接口

还有一些感觉用不到,如有需要可以访问上篇转载的文章

差点忘了pom依赖

org.apache.shiro shiro-spring 1.2.3

此外我们还可以通过拦截器控制url拦截

自定义拦截器PermissionInterceptor

import com.youotech.login.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**

  • 自定以接口控制拦截器
    */
    @Component
    public class PermissionInterceptor implements HandlerInterceptor {

    @Autowired
    LoginService loginService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    try {
    StringBuffer requestURL = request.getRequestURL();
    String url = requestURL.toString();
    //打印路径信息,作为后台日志进行查看
    System.out.println(url);
    if (url.contains("/sys/login")) {
    return HandlerInterceptor.super.preHandle(request, response, handler);
    }
    if (url.contains("/sys/logout")) {
    return HandlerInterceptor.super.preHandle(request, response, handler);
    }
    if (url.contains("/sys/getVerifyCode")) {
    return HandlerInterceptor.super.preHandle(request, response, handler);
    }
    if (url.contains("/sys/getLoginUserInfo")) {
    return HandlerInterceptor.super.preHandle(request, response, handler);
    }
    //判断权限信息
    List urlList = loginService.getData();
    if (urlList != null && urlList.size() > 0) {
    for (String qxurl : urlList) {
    if (url.contains(qxurl)) {
    return HandlerInterceptor.super.preHandle(request, response, handler);
    } else {
    response.setStatus(401);
    return false;
    }
    }
    } else {
    response.setStatus(401);
    return false;
    }
    return false;
    } catch (Exception e) {
    response.setStatus(401);
    return false;
    }
    }
    }

注册拦截器

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyConfig implements WebMvcConfigurer {

@Bean
public PermissionInterceptor myInterceptor(){
    return new PermissionInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
    // 使拦截器生效1.此处参数是我们自定义的拦截器名( LoginInterceptor ) 2.添加拦截规则(/**)拦截全部
    registry.addInterceptor(myInterceptor()).addPathPatterns("/**");
    WebMvcConfigurer.super.addInterceptors(registry);
}

}

以上权限基本配完但是存在一个问题,那就是如果session过期怎么办,难道让前端一直卡着??

所以在ShiroUserFilter中继续配置

import com.youotech.login.entity.SysUserEntity;
import org.apache.shiro.web.filter.authc.UserFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**

  • 重写shiro的UserFilter,实现通过OPTIONS请求

  • @author MDY
    */
    public class ShiroUserFilter extends UserFilter {

    /**

    • 在访问过来的时候检测是否为OPTIONS请求,如果是就直接返回true
      */
      @Override
      protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
      HttpServletResponse httpResponse = (HttpServletResponse) response;
      HttpServletRequest httpRequest = (HttpServletRequest) request;
      //从session中获取用户信息
      SysUserEntity comUser = (SysUserEntity)ShiroSessionUtils.getAttribute(“loginUser”);
      // session过期
      if (comUser == null) {
      returnJson(httpResponse, “{“code”:510,“msg”:“session is expired!”}”);
      setHeader(httpRequest, httpResponse);
      return false;
      }
      if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
      setHeader(httpRequest, httpResponse);
      return true;
      }
      return super.preHandle(httpRequest, response);
      }

    /返回客户端数据/
    private void returnJson(HttpServletResponse response, String json) throws Exception{
    PrintWriter writer = null;
    response.setCharacterEncoding(“UTF-8”);
    response.setContentType(“text/html; charset=utf-8”);
    try {
    writer = response.getWriter();
    writer.print(json);

     } catch (IOException e) {
     } finally {
         if (writer != null)
             writer.close();
     }
    

    }

    /**

    • 该方法会在验证失败后调用,这里由于是前后端分离,后台不控制页面跳转
    • 因此重写改成传输JSON数据
      */
      @Override
      protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
      saveRequest(request);
      setHeader((HttpServletRequest) request, (HttpServletResponse) response);
      PrintWriter out = response.getWriter();
      //自己控制返回的json数据
      //out.println(new Result(ResultStatusCode.SHIRO_ERROR));
      out.flush();
      out.close();
      }

    /**

    • 为response设置header,实现跨域
      */
      private void setHeader(HttpServletRequest request, HttpServletResponse response) {
      //跨域的header设置
      response.setHeader(“Access-control-Allow-Origin”, request.getHeader(“Origin”));
      response.setHeader(“Access-Control-Allow-Methods”, request.getMethod());
      response.setHeader(“Access-Control-Allow-Credentials”, “true”);
      response.setHeader(“Access-Control-Allow-Headers”, request.getHeader(“Access-Control-Request-Headers”));
      //防止乱码,适用于传输JSON数据
      response.setHeader(“Content-Type”, “application/json;charset=UTF-8”);
      response.setStatus(HttpStatus.OK.value());
      }
      }

但是前端会结束不到相应的response值,打开f12一看跨域,所以在启动类中加上跨域

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@SpringBootApplication(exclude ={DataSourceAutoConfiguration.class})
@MapperScan({“com.youotech..dao"})
@EnableTransactionManagement
@EnableCaching
@ServletComponentScan
@EnableScheduling
@CrossOrigin(allowCredentials = “true”, allowedHeaders = "
”)

public class CzbdzApplication {

public static void main(String[] args) {
    SpringApplication.run(CzbdzApplication.class, args);
}

/**
 * 跨域问题
 * @return
 */
@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);

// config.addAllowedOrigin(“http://localhost:9000”);
config.addAllowedOrigin("");
config.addAllowedHeader("
");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source) );
bean.setOrder(0);
return bean;
}
}

解决角色无权限后端异常问题工具类

import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

/**

  • 统一异常处理类
  • 捕获程序所有异常,针对不同异常,采取不同的处理方式

*/
@ControllerAdvice
public class ExceptionHandleController {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandleController.class);

@ResponseBody
@ExceptionHandler(UnauthorizedException.class)
public Map<String,Object> handleShiroException(Exception ex) {
    HashMap<String, Object> map = new HashMap<>();
    map.put("code",512);
    return map;
}

}

配置加密解密(采用base对称加密与MD5非对称加密)

修改!!!shiorUtil内参数:改为MD5加密方式

/**  加密算法 */
public final static String hashAlgorithmName = "MD5";

public static String MD5(String password, String salt) {
	return new SimpleHash(hashAlgorithmName, password, salt, hashIterations).toString();
}

userRealm类添加

//MD5加密
    String pw = new String(token.getPassword());
    String password  = Base64Utils.dec(pw);
    String credentials =ShiroUtils.MD5(password,"salt");

    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    token.setPassword(credentials.toCharArray());
    //清除之前的授权信息
    super.clearCachedAuthorizationInfo(info.getPrincipals());
    return info;

base64工具类

mport sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.util.Base64;

/**

  • Created by Liuxd on 2018-11-02.
    */
    public class Base64Utils {

    public static void main(String[] args) throws Exception {
    String str = “123456”;
    base64(str);
    enAndDeCode(str);

    }

    public static String dec(String str){
    byte[] bytes = str.getBytes();
    byte[] decoded = Base64.getDecoder().decode(str);
    String decodeStr = new String(decoded);
    return decodeStr;
    }
    /**

    • Base64

    */
    public static void base64(String str) {
    byte[] bytes = str.getBytes();
    //Base64 加密
    String encoded = Base64.getEncoder().encodeToString(bytes);
    System.out.println(“Base 64 加密后:” + encoded);
    //Base64 解密
    byte[] decoded = Base64.getDecoder().decode(encoded);
    String decodeStr = new String(decoded);
    System.out.println(“Base 64 解密后:” + decodeStr);
    System.out.println();
    }

    /**

    • BASE64加密解密
      */
      public static void enAndDeCode(String str) throws Exception {
      String data = encryptBASE64(str.getBytes());
      System.out.println(“sun.misc.BASE64 加密后:” + data);

      byte[] byteArray = decryptBASE64(data);
      System.out.println(“sun.misc.BASE64 解密后:” + new String(byteArray));
      }

    /**

    • BASE64解密
    • @throws Exception
      */
      public static byte[] decryptBASE64(String key) throws Exception {
      return (new BASE64Decoder()).decodeBuffer(key);
      }

    /**

    • BASE64加密
      */
      public static String encryptBASE64(byte[] key) throws Exception {
      return (new BASE64Encoder()).encodeBuffer(key);
      }
      }

比较类方法doCredentialsMatch

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;

public class CredentialsMatcher extends SimpleCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken utoken=(UsernamePasswordToken) token;
//获得用户输入的密码:(可以采用加盐(salt)的方式去检验)
String inPassword = new String(utoken.getPassword());
//获得数据库中的密码
String dbPassword=(String) info.getCredentials();
//进行密码的比对
return this.equals(inPassword, dbPassword);
}

相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页