zoukankan      html  css  js  c++  java
  • Shiro——认证

    引入shiro依赖

            <!-- shiro -->
            <dependency> <!-- shiro-core Required in all environments. -->
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-core</artifactId>
                <version>${shiro.version}</version>
            </dependency>
            <dependency> <!-- Enables support for web-based applications. -->
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-web</artifactId>
                <version>${shiro.version}</version>
            </dependency>
            <dependency> <!-- Enables AspectJ support for Shiro AOP and Annotations. -->
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-aspectj</artifactId>
                <version>${shiro.version}</version>
            </dependency>
            <dependency> <!-- Enables Spring Framework integration. -->
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>${shiro.version}</version>
            </dependency>
            <!-- -->

    web.xml中添加ShiroFilter

    • Shiro 提供了与 Web 集成的支持,其通过一个ShiroFilter 入口来拦截需要安全控制的URL,然后进行相应的控制
    • ShiroFilter 类似于如 Strut2/SpringMVC 这种web 框架的前端控制器,是安全控制的入口点,其负责读取配置(如ini 配置文件),然后判断URL是否需要登录/权限等工作。、
    • DelegatingFilterProxy 作用是自动到 Spring 容器查找名字为 shiroFilter(filter-name)的 bean 并把所有 Filter的操作委托给它。
     <!-- Shiro Filter is defined in the spring application context: -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
    
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

    spring核心配置文件中配置shiro

       <!-- 自定义Realm -->
        <bean id="JdbcRealm" class="com.nchu.shiro.JdbcRealm" ></bean>
    
        <!-- 安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="JdbcRealm"/>
        </bean>
    
        <!-- shiroFilter /pub/** = anon -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="loginUrl" value="/shiro/login.jsp" />
            <property name="successUrl" value="/shiro/list.jsp"/>
            <property name="unauthorizedUrl" value="/shiro/unauthorized.jsp"/>
            <property name="securityManager" ref="securityManager"/>
            <!--1).anon可以被匿名访问
                2).authc被认证后可被访问,没有认证会被重定向到loginUrl指定的页面
                3).logout登出-->
            <property name="filterChainDefinitions">
                <value>
                    /login       = anon
                    /shiro/login = anon
                    /shiro/logout=logout
                    /**          = authc
                </value>
            </property>
        </bean>
    
        <!-- Shiro生命周期处理器-->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    身份验证

    • 身份验证:一般需要提供如身份 ID 等一些标识信息来表明登录者的身份,如提供 email,用户名/密码来证明。
    • 在 shiro 中,用户需要提供 principals (身份)和 credentials(证明)给 shiro,从而应用能验证用户身份:
    • principals:身份,即主体的标识属性,可以是任何属性,如用户名、邮箱等,唯一即可。一个主体可以有多个 principals,但只有一个Primary principals,一般是用户名/邮箱/手机号。
    • credentials证明/凭证,即只有主体知道的安全值,如密码/数字证书等。
    • 最常见的 principals 和 credentials 组合就是用户名/密码

    Shiro 认证流程

    1、前端请求

      1). 创建一个表单页面:login.jsp

    <%--
      Created by IntelliJ IDEA.
      User: root
      Date: 2018/1/16 0016
      Time: 19:16
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <h2>Login Page</h2>
    
    <form action="${pageContext.request.contextPath}/shiro/login" method="post">
        UserName : <input type="text" name="username">
        <br><br>
        PassWord : <input type="password" name="password">
        <br><br>
        <input type="submit" value="登录">
    </form>
    </body>
    </html>
    View Code

      2). 把请求提交到 SpringMVC 的 Handler
      3). Handler获取用户名和密码.

    2、获取当前的 Subject. 调用 SecurityUtils.getSubject();

    3、测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated() 

    4、若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象

    5、执行登录: 调用 Subject 的 login(AuthenticationToken) 方法.

    package com.nchu.shiro;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.subject.Subject;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    /**
     * Created by yangshijing on 2018/1/16 0016.
     */
    @Component
    @RequestMapping("/shiro")
    public class ShiroController {
        public static  final String SUCCESS = "success";
        @RequestMapping("/login")
        public String login(@RequestParam("username") String username,@RequestParam("password") String password){
            //获取当前的 Subject
            Subject currentUser = SecurityUtils.getSubject();
            //判断当前的用户是否已经被认证
            if (!currentUser.isAuthenticated()) {
                //若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
                UsernamePasswordToken token = new UsernamePasswordToken(username, password);
                token.setRememberMe(true);
                try {
                    //测试token是否和自定义中的Realm的入参token相同
                    System.out.println("++++++++>"+token.hashCode());
                    // 执行登录
                    currentUser.login(token);
    
                }
                catch (AuthenticationException ae) {
                    System.out.print("登录失败");
                    return "error";
                }
            }
            return "redirect:/shiro/list.jsp";
    
        }
    }
    View Code

    6、自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.

    1). 需要继承 org.apache.shiro.realm.AuthenticatingRealm 类
    2). 实现 doGetAuthenticationInfo(AuthenticationToken token) 方法.

    7、由 shiro 完成对密码的比对.

    package com.nchu.shiro;
    
    import com.nchu.mvc.bean.PracticeUser;
    import com.nchu.mvc.dao.ShiroRealmMapper;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.realm.AuthenticatingRealm;
    import org.springframework.beans.factory.annotation.Autowired;
    
    /**
     * Created by yangshijing on 2018/1/16 0016.
     */
    public class JdbcRealm extends AuthenticatingRealm {
        @Autowired
        ShiroRealmMapper shiroRealmMapper;
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("----->"+token.hashCode());
            //1. 把 AuthenticationToken 转换为 UsernamePasswordToken
            UsernamePasswordToken upToken = (UsernamePasswordToken) token;
    
            //2. 从 UsernamePasswordToken 中来获取 username
            String username = upToken.getUsername();
    
            //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
    
            System.out.println("从数据库中获取 username: " + username + " 所对应的用户信息.");
            String password  = shiroRealmMapper.login(username);
            //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常
            if(password==null){
                throw new UnknownAccountException("用户不存在!");
            }
    
            //5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常.
            /*  if("monster".equals(username)){
                throw new LockedAccountException("用户被锁定");
            }*/
            //6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 
            //通常使用的实现类为: SimpleAuthenticationInfo
            //以下信息是从数据库中获取的.
            //1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象.
            Object principal = username;
            //2). credentials: 密码.
            Object credentials = password;
            //3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
            String realmName = getName();
            SimpleAuthenticationInfo info =
     new SimpleAuthenticationInfo(principal, credentials, realmName);
            return info;
        }
    }
               
    View Code

    mybatis框架从数据库中查询

    mapper接口

    package com.nchu.mvc.dao;
    import org.springframework.stereotype.Component;
    /**
     * Created by yangshijing on 2018/1/16 0016.
     */
    @Component
    public interface ShiroRealmMapper {
    
        String  login(String username);
    }
    mapper映射文件
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.nchu.mvc.dao.ShiroRealmMapper">
        <select id="login" resultType="java.lang.String">
            SELECT password FROM practice_user
            Where user_name=#{userName}
        </select>
    
    </mapper>
  • 相关阅读:
    Codeforces 1485C Floor and Mod (枚举)
    CodeForces 1195D Submarine in the Rybinsk Sea (算贡献)
    CodeForces 1195C Basketball Exercise (线性DP)
    2021年初寒假训练第24场 B. 庆功会(搜索)
    任务分配(dp)
    开发工具的异常现象
    Telink MESH SDK 如何使用PWM
    Telink BLE MESH PWM波的小结
    [LeetCode] 1586. Binary Search Tree Iterator II
    [LeetCode] 1288. Remove Covered Intervals
  • 原文地址:https://www.cnblogs.com/realshijing/p/8299245.html
Copyright © 2011-2022 走看看