0
点赞
收藏
分享

微信扫一扫

Shrio授权 -- SSM

愚鱼看书说故事 2022-04-14 阅读 23
java

一、Shiro授权流程

承接上一篇博客的内容,我们这回来做shiro的授权

授权可简单理解为who对what(which)进行How操作:

Who,即主体(Subject)What,即资源(Resource)How,权限/许可(Permission)

授权:认证通过后就会进行授权,通过用户名到数据库中查询用户的角色和权限信息然后返回判断

二、Shrio权限案例

1.首先我们在SysMapper中新增两个方法与sql

    //根据username查询该用户的所有角色,用于角色验证
    Set<String> findRoles(@Param("username") String username);

    //根据username查询他所拥有的权限信息,用于权限判断
    Set<String> findPermissions(@Param("username") String username);
-------------------------------------------------------------------------
    <select id="findRoles" resultType="java.lang.String">
      select
        r.rolename
      from
        t_sys_user u,t_sys_user_role ur,t_sys_role r
      where
        u.userid=ur.userid and ur.roleid=r.roleid
      and u.username=#{username}
    </select>
  <select id="findPermissions" resultType="java.lang.String">
    select
        p.permission
    from
        t_sys_user u,t_sys_user_role ur,t_sys_role r,t_sys_role_permission  rp,t_sys_permission p
    where
        u.userid=ur.userid and ur.roleid=r.roleid and r.roleid=rp.roleid and rp.perid=p.perid
    and u.username=#{username}
  </select>

2.自定义Realm配置Shiro授权认证

package com.zking.ssm.book.shiro;

import com.zking.ssm.book.mapper.SysUserMapper;
import com.zking.ssm.book.model.SysUser;
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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * 自定义Realm的安全数据源,采用数据库的方式
 */
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private SysUserMapper sysUserMapper;


    /**
     *授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取登录账号
        String username = principalCollection.getPrimaryPrincipal().toString();
        //根据username获取用户对应角色
        Set<String> roles = sysUserMapper.findRoles(username);
        //根据username获取对应的角色权限
        Set<String> permissions = sysUserMapper.findPermissions(username);
        //创建SimpleAuthorizationInfo
        SimpleAuthorizationInfo simple=new SimpleAuthorizationInfo();
        //填充用户的角色和权限
        simple.setRoles(roles);
        simple.setStringPermissions(permissions);

        return simple;
    }

    /**
     * 认证
     * @param authenticationToken 传入的账号密码令牌Token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取账号
        String username = authenticationToken.getPrincipal().toString();
        //获取密码
        String password = authenticationToken.getCredentials().toString();

        //根据账号查询数据库中的用户对象信息
        SysUser sysUser = sysUserMapper.userLogin(username);
        //判断账号是否存在
        if(sysUser ==null){
            throw new UnknownAccountException("账号不存在!!!");
        }

        //创建SimpleAuthenticationInfo,传入正确的账号和密码(来自于数据库)
        SimpleAuthenticationInfo simple=new SimpleAuthenticationInfo(
                sysUser.getUsername(),
                sysUser.getPassword(),
                ByteSource.Util.bytes(sysUser.getSalt()),
                this.getName()
        );

        return simple;
    }
}

3.简单登录测试

4.使用Shiro标签实现权限验证

 1.导入 Shiro 标签库

 <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
Shiro标签库:
  guest标签 :验证当前用户是否为“访客”,即未认证(包含未记住)的用户
  user标签 :认证通过或已记住的用户
  authenticated标签 :已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在
  notAuthenticated标签 :未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户
  principal 标签 :输出当前用户信息,通常为登录帐号信息 
  hasRole标签 :验证当前用户是否属于该角色 
  lacksRole标签 :与hasRole标签逻辑相反,当用户不属于该角色时验证通过
  hasAnyRole标签 :验证当前用户是否属于以下任意一个角色
  hasPermission标签 :验证当前用户是否拥有指定权限
  lacksPermission标签 :与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过 

2.在主页面设置查看权限

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags"   %>
<html>
<head>
    <title>Title</title>
     <%@include file="/common/head.jsp"%>
</head>
<body>
<h1>首页${pageContext.request.contextPath}</h1>
<div style="float: right;right: 10px;top: 10px;">
    <a href="${pageContext.request.contextPath}/user/userLogout">退出</a>
</div>

<%--<img src="img/fgs.jpg" width="800px" height="500px"/>
<img src="images/yhtx.jpg" width="800px" height="500px"/><br>--%>
<%--相对路径--%>
<a href="${pageContext.request.contextPath}/book/addBook">书本新增</a><br>
<%--绝对路径  加项目路径的方式--%>

<shiro:hasPermission name="bookmanager:book:query">
<a href="${pageContext.request.contextPath}/book/bookList">书本列表</a><br>
</shiro:hasPermission>

<a href="${pageContext.request.contextPath}/tohellow">进入欢迎页面</a><br>


<hr>
<h1>查询返回JSON数据</h1>
<ol>
    <shiro:hasRole name="管理员">
        <li><a href="${ctx}/book/queryListBooks">查询返回List&lt;T&gt;格式的JSON数据</a></li>
        <li><a href="${ctx}/book/querySingleBook?bookId=167">查询返回单个实体格式的JSON数据</a></li>
        <li><a href="${ctx}/book/querySingleMap?bookId=15">查询返回Map类型的JSON数据</a></li>
        <li><a href="${ctx}/book/queryMapList">查询返回List&lt;Map&gt;的JSON数据</a></li>
        <li><a href="${ctx}/book/queryhybridBooks">查询返回JSON混合格式的数据</a></li>
        <li><a href="${ctx}/book/queryString">查询返回Sting类型的JSON数据</a></li>
    </shiro:hasRole>

</ol>

3.测试

登录zhangsan没有查看权限

 5.注解式开发

常用注解

  @RequiresAuthenthentication:表示当前Subject已经通过login进行身份验证;即 Subjecj.isAuthenticated()返回 true
  @RequiresUser:表示当前Subject已经身份验证或者通过记住我登录的
  @RequiresGuest:表示当前Subject没有身份验证或者通过记住我登录过,即是游客身份
  @RequiresRoles(value = {"admin","user"},logical = Logical.AND):表示当前Subject需要角色admin和user
  @RequiresPermissions(value = {"user:delete","user:b"},logical = Logical.OR):表示当前Subject需要权限user:delete或者user:b

1.在spring-mvc.xml中加入shiro注解式权限

    <!--9、配置Shiro注解式权限-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true"/>
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

2.在控制层方法上加上注解

    /**
     * 返回List泛型格式的JSON数据
     * @param book
     * @param request
     * @return
     */
    @RequiresRoles("管理员")
    @RequestMapping("/queryListBooks")
    @ResponseBody
    public List<Book> queryListBooks(Book book,HttpServletRequest request){
        PageBean pageBean=new PageBean();
        pageBean.setRequest(request);
        List<Book> books = bookService.queryBookPager(book, pageBean);
        return   books;
    };


    /**
     * 返回Map类型的JSON数据
     * @param bookId
     * @return
     */
    @RequiresPermissions("bookmanager:book:edit")
    @RequestMapping("/querySingleMap")
    @ResponseBody
    public Map<String, Object> querySingleMap(Integer bookId){
        return  bookService.querySingleMap(bookId);
    }

3.增加全局异常处理

package com.zking.ssm.book.exception;


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.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

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


/**
 * SpingMVC提供的第三种种全局异常处理方式
 * 1)@ControllerAdvice +@ExceptionHandler
 * 2)@RestControllerAdvice +@ExceptionHandler
 *      @RestControllerAdvice ==@Controller +@ResponseBody 返回JSON的数据格式,绕开视图解析器
 */
//@ControllerAdvice
@RestControllerAdvice
public class GlobalException2{
        /*@ExceptionHandler
        public ModelAndView exceptionHandler(Exception e){
            ModelAndView mv=new ModelAndView();
            mv.setViewName("error");
            //判断异常类型
            if(e instanceof BusinessException){
            BusinessException ex=(BusinessException)e;
                mv.addObject("msg","系统繁忙,请稍后再试.......");
            }

            //强制更换视图解析器  不跳页面!!!
            mv.setView(new MappingJackson2JsonView());
            return mv;
        }*/

        @ExceptionHandler
        public Map<String, Object> exceptionHandler(Exception e){
            e.printStackTrace();
            Map<String, Object> json=new HashMap();
            //判断异常类型
            if(e instanceof BusinessException){
                json.put("msg","系统繁忙,请稍后再试.......");
                json.put("code",500);
            }else if(e instanceof UnauthorizedException){
                json.put("msg","未授权的操作,请与管理员联系.......");
                json.put("code",500);
            }else{
                json.put("msg","内部错误.......");
                json.put("code",500);
            }

            return json;
        }
}

6.测试

把前面的标签注释,然后登录zhangsan,点击加了权限的方法

 

举报

相关推荐

0 条评论