shiro进行登录认证和授权

1.Shiro核心架构ababab

三个常用过滤器

anno:不需要任何权限即可访问资源
authc:需要登录的权限才可以访问资源
perms:需要指定的权限才能访问目标资源

2.shiro登录认证

使用认证过滤器
1.在shiro的xml文件中添加认证过滤器,创建shiroFilterFactoryBean,创建securityManager对象,创建自定义的realm
例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--该文件的作用spring整合shiro-->

    <!--1. 创建ShiroFilterFactoryBean对象-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!--配置SecurityManager的属性-->
        <property name="securityManager" ref="securityManager"/>
        <!--配置shiro过滤器-->
        <property name="filterChainDefinitions">
            <value>
            <!--    /* : 匹配一级目录
                   /** :匹配多级或者一级目录

                静态资源是需要无条件放行,登陆的方法也是需要无条件放行,
                shiro默认是对登录页面无条件放行的,而且默认等于页面的名字为login.jsp/
            -->
                /css/**=anon
                /img/**=anon
                /make/**=anon
                /plugins/**=anon
                /login.do=anon
                /**=authc
            </value>
        </property>
        <!--配置默认的登录页面-->
        <property name="loginUrl" value="/login2.jsp"/>
    </bean>

    <!--2.创建securityManager对象-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!--securityManager本质上是会调用realm的方法-->
        <property name="realm" ref="realm"/>
    </bean>

    <!--3. 创建realm,需要自定义的-->
    <bean id="realm" class="cn.itcast.web.shiro.AuthRealm"/>

</beans>

控制层的登录认证
1.得到subject对象,将账号(邮箱)密码封装到token,发出登录请求登录成功得到一个登录成功对象
例:

@Controller
public class LoginController extends  BaseController {


    @Autowired
    private UserService userService;

    @Autowired
    private ModuleService moduleService;

  
     /*
        url: /login.do
        作用:校验登陆
        参数:email(邮箱) ,password(密码)
        返回值: 登陆成功 home/main(后台首页) || 登陆失败: login.jsp()
     */
    @RequestMapping("/login")
    public String login(String email,String password){
        //1. 判断用户名与密码是否为空,如果两者有一者为空都是回到登陆页面
        if(StringUtils.isEmpty(email)||StringUtils.isEmpty(password)){
            request.setAttribute("error","用户名或者密码不能为空");
            //注意: login.jsp不在pages目录中,所以不要经过视图解析器,所以前面带上forward或者redirect
            return "forward:/login.jsp";
        }
        try {
            //2. 得到subject的对象
            Subject subject = SecurityUtils.getSubject();
            //3. 把邮箱与密码封装到Token里面
            UsernamePasswordToken token = new UsernamePasswordToken(email,password);

            //4. 使用subject发出登陆的请求,携带token过去, 这里的登录方法本质上是会调用realm里面的登陆方法
            subject.login(token);

            //5. 登陆成功得到一个登陆成功的对象, shiro登陆成功之后其实shiro本质上也会在session中做很多登陆成功标记
            User loginUser = (User) subject.getPrincipal();
            //这里做的不是登录成功标记,而且我们页面上需要使用登陆者的信息,所以我们保存登陆者的信息
            session.setAttribute("loginUser",loginUser);

            //6. 查看该登陆成功的用户的权限
            List<Module> moduleList = moduleService.findModuleByUser(loginUser);
            session.setAttribute("modules",moduleList);
            //返回到后台的首页
            return "home/main";
        } catch (UnknownAccountException e) { //如果一旦出现了该异常,代表不存在用户名
           request.setAttribute("error","用户名或者密码错误");
           return "forward:/login.jsp";
        }catch (IncorrectCredentialsException e){ //密码错误的异常
            request.setAttribute("error","用户名或者密码错误");
            return "forward:/login.jsp";
        }

    }

}

编写AuthRealm,实现登录认证
根据token转为用户名、密码,根据用户名查找用户,存在用户则对比密码
例:

public class AuthRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;


    //登录认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1. 先把token强制UsernamePasswordToken
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

        //2. 得到邮箱与密码
        String email = usernamePasswordToken.getUsername();
       // String password = new String(usernamePasswordToken.getPassword()); //用户输入的密码

        //3. 根据邮箱去数据库查找一个用户
        User dbUser = userService.findByEmail(email);

        //4. 如果查找到的用户等于null,代表用户名不存在,直接返回null即可。当你返回null的时候,subject.login方法会接收到一个异常
        if(dbUser==null){
            return null;
        }

        //5. 如果用户存在,那么则通知shiro去对比密码
        /*
        SimpleAuthenticationInfo(Object principal, Object credentials, String realmName)
                principal: 登陆成功返回给controller登录成功对象
                credentials : 该用户在数据库中的密码
                realmName: 不需要管理
         */

        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(dbUser,dbUser.getPassword(),"");

        return simpleAuthenticationInfo;
    }
}

对密码加盐加密,编写自定义加盐加密匹配器,增加用户时进行加盐加密,注销用户需销毁session在shiro中的标记。

3.shiro授权

如何实现授权?分为以下两个步骤==

  1. 登陆认证成功后,获取用户的权限 (给该用户分配对应的权限)
  2. 访问资源时候,进行授权校验:用访问资源需要的权限去用户权限列表查找,如果存在,则有权限访问资源。(权限拦截)

shiro提供了四种方式实现权限校验:
1) 硬编码方式(拦截方法)(非Web应用,Web应用)

Subject subject = SecurityUtils.getSubject();
subject.checkPermission("部门管理");

2) 过滤器配置方式(拦截url)(Web应用)

/system/user/list.do = perms["用户管理"]

3) 注解方式(拦截方法)(Web应用)

@RequiresPermissions(“”)

4) shiro提供的标签((拦截页面元素:按钮,表格等))(Web应用)

<shiro:hasPermission name="用户管理">
    <a href="#">用户管理</a>
</shiro:hasPermission>

实现自定义realm的doGetAuthorizationInfo()方法,返回用户已经具有的权限。

例:

public class AuthRealm extends AuthorizingRealm {


    @Autowired
    private UserService userService;

    @Autowired
    private ModuleService moduleService;
//授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //1. 获取到登陆成功对象
        User loginUser = (User) principals.getPrimaryPrincipal();
        //2. 查询登陆用户拥有的权限
        List<Module> moduleList = moduleService.findModuleByUser(loginUser);

        //3.把权限添加到AuthorizationInfo对象中,这个对象拥有的权限则代表了当前用户拥有权限
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //4. 遍历用户的权限,把权限唯一标识添加到authorizationInfo对象里面
        for (Module module : moduleList) {
            authorizationInfo.addStringPermission(module.getName());//权限标记一般我们都添加
        }

        return authorizationInfo;
    }
}
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值