Shiro-认证

认证流程:

1. 获取当前的 Subject. 调用 SecurityUtils.getSubject();
2. 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated()
3. 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
1). 创建一个表单页面
2). 把请求提交到 SpringMVC 的 Handler
3). 获取用户名和密码.
4. 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法.
5. 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.
1). 实际上需要继承 org.apache.shiro.realm.AuthenticatingRealm 类
2). 实现 doGetAuthenticationInfo(AuthenticationToken) 方法.
6. 由 shiro 完成对密码的比对.

实现过程:

  创建一个login.jsp

  

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

    <h4>Login Page</h4>
    <form action="shiro/login" method="post">
        username: <input type="text" name="userName"/>
        <br><br>

        password: <input type="password" name="password" />
        <br><br>

        <input type="submit" value="Submit"/>
    </form>

</body>
</html>

登录成功后的list.jsp  包含登出按钮

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

    <h4>List Page</h4>

    <a href="shiro/logout">Logout</a>
</body>
</html>

创建一个Controller  ShiroHandler.java

package com.java.shiro.realms;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/shiro")
public class ShiroHandler {

    @RequestMapping("/login")
    public String login(@RequestParam("userName") String userName,
            @RequestParam("password") String password) {

        Subject currentUser = SecurityUtils.getSubject();

        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(userName,
                    password);
            token.setRememberMe(true);
            try {
                currentUser.login(token);
            } catch (AuthenticationException e) {
                System.out.println("登录失败:" + e.getMessage());
            }
        }
        return "redirect:/list.jsp";

    }

}

创建一个Realm 重写AuthenticatingRealm 的doGetAuthenticationInfo()

package com.java.shiro.realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.AuthenticatingRealm;

public class ShiroRealm extends AuthenticatingRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("doGetAuthenticationInfo " + token);

        // 1. 把AuthenticationToken 转换为UsernamePasswordToken
        UsernamePasswordToken up = (UsernamePasswordToken) token;
        // 2. 从UsernamePasswordToken 中来获取username
        String username = up.getUsername();
        // 3. 调用数据库的方法,从数据库中查询username对应的用户记录
        System.out.println("从数据库中获取userName :" + username + " 所对应的用户信息.");
        // 4. 若用户不存在,则可以抛出 UnknownAccoountException 异常
        if ("unknown".equals(username)) {
            throw new UnknownAccountException("用户不存在");
        }
        // 5. 根据用户信息的情况,决定是否需要抛出其他的AuthencationException 异常 假设用户被锁定
        if ("monster".equals(username)) {
            throw new LockedAccountException("用户被锁定");
        }
        // 6. 根据用户的情况,来构建AuthenticationInfo 对象并返回,通常使用的是
        // SimpleAuthenticationInfo
        // 以下信息是从数据库获取的.

        Object principal = username; // principal 认证的实体信息.
                                        // 可以是username,也可以是数据表对应的用户的实体类对象
        String credentials = "123456"; // credentials:密码
        String realmName = getName();
        AuthenticationInfo info = new SimpleAuthenticationInfo(principal,
                credentials, realmName);

        return info;
    }

}

在applicationContext.xml 中添加对应的 过滤器

<?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">

    <!-- 数据源配置,暂时不考虑数据源,做一些静态的数据 -->
    <!-- Sample RDBMS data source that would exist in any application - not Shiro related. -->
    <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
        <property name="url" value="jdbc:hsqldb:mem:shiro-spring"/>
        <property name="username" value="sa"/>
    </bean> -->
    <!-- Populates the sample database with sample users and roles. -->
    <!-- <bean id="bootstrapDataPopulator" class="org.apache.shiro.samples.spring.BootstrapDataPopulator">
        <property name="dataSource" ref="dataSource"/>
    </bean> -->

    <!-- Simulated business-tier "Manager", not Shiro related, just an example -->
    <!-- <bean id="sampleManager" class="org.apache.shiro.samples.spring.DefaultSampleManager"/> -->

    <!-- =========================================================
         Shiro Core Components - Not Spring Specific
         ========================================================= -->
    <!-- Shiro‘s main business-tier object for web-enabled applications
         (use DefaultSecurityManager instead when there is no web environment)-->
    <!--
        1.配置SecurityManager!
    -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager"/>
        <!-- Single realm app.  If you have multiple realms, use the ‘realms‘ property instead. -->
        <!-- 配置session的管理方式 -->
        <!-- <property name="sessionMode" value="native"/> -->
        <property name="realm" ref="jdbcRealm"/>
    </bean>

    <!-- Let‘s use some enterprise caching support for better performance.  You can replace this with any enterprise
         caching framework implementation that you like (Terracotta+Ehcache, Coherence, GigaSpaces, etc -->
    <!--
        2.配置CacheManager,实例上可以用企业的缓存产品来提升性能
        2.1需要加入ehcache的jar包及配置文件
     -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <!-- Set a net.sf.ehcache.CacheManager instance here if you already have one.  If not, a new one
             will be creaed with a default config:
             <property name="cacheManager" ref="ehCacheManager"/> -->
        <!-- If you don‘t have a pre-built net.sf.ehcache.CacheManager instance to inject, but you want
             a specific Ehcache configuration to be used, specify that here.  If you don‘t, a default
             will be used.: -->
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
    </bean>

    <!-- Used by the SecurityManager to access security data (users, roles, etc).
         Many other realm implementations can be used too (PropertiesRealm,
         LdapRealm, etc. -->
    <!--
        3.配置Realm
        3.1 自己写一个Realm,需要实现Realm接口
     -->
    <bean id="jdbcRealm" class="com.java.shiro.realms.ShiroRealm"></bean>

    <!-- =========================================================
         Shiro Spring-specific integration
         ========================================================= -->
    <!-- Post processor that automatically invokes init() and destroy() methods
         for Spring-configured Shiro objects so you don‘t have to
         1) specify an init-method and destroy-method attributes for every bean
            definition and
         2) even know which Shiro objects require these methods to be
            called. -->

    <!--
        4.配置 LifecycleBeanPostProcessor,可以自动的调用配置在spring IOC容器中Shiro bean的声明周期方法
     -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- Enable Shiro Annotations for Spring-configured beans.  Only run after
         the lifecycleBeanProcessor has run: -->
    <!--
        5.启用 IOC 容器中使用 shiro 注解,但必须在配置了LifecycleBeanPostProcessor 之后才可以使用。
     -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

    <!-- Secure Spring remoting:  Ensure any Spring Remoting method invocations can be associated
         with a Subject for security checks. -->
    <!-- 远程调用,暂时不需要 -->
    <!-- <bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
        <property name="securityManager" ref="securityManager"/>
    </bean> -->

    <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -
         web.xml uses the DelegatingFilterProxy to access this bean.  This allows us
         to wire things with more control as well utilize nice Spring things such as
         PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: -->

    <!--
        6.配置ShiroFilter
        6.1 id 必须和web.xml 中配置的 DelegatingFilterProxy 的 <filter-name> 一致
            若不一致,则会抛出:NoSuchBeanDefinitionException.因为Shiro会来IOC容器中查找和<filter-name> 名字对应的filter bean.
     -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login.jsp"/><!-- 登录页面 -->
        <property name="successUrl" value="/list.jsp"/><!-- 登录成功页面 -->
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/><!-- 没有权限的页面 -->
        <!-- The ‘filters‘ property is not necessary since any declared javax.servlet.Filter bean
             defined will be automatically acquired and available via its beanName in chain
             definitions, but you can perform overrides or parent/child consolidated configuration
             here if you like: -->
        <!-- <property name="filters">
            <util:map>
                <entry key="aName" value-ref="someFilterPojo"/>
            </util:map>
        </property> -->
        <!--
            配置哪些页面需要受保护
            以及访问这些页面需要的权限
            1). anon(anonymous) 可以被匿名访问,即不需要登录就可以访问
            2). authc(authentication) 必须认证之后,即登录后才可以访问
            3). URL 权限采取第一次匹配优先的方式,即从开头使用第一个匹配的url模式对应的拦截器链。
             4). logout 登出
         -->
        <property name="filterChainDefinitions">
            <value>
                /login.jsp= anon
                /shiro/login= anon
                /shiro/logout = logout
                # everything else requires authentication:

                /** = authc
            </value>
        </property>
    </bean>

</beans>

在登录成功后,点击后退,再次随便输入依旧能够登录成果,是由于缓存的作用。

密码的比对:

通过AuthenticatingRealm  的 credentialsMatcher 属性进行的比对

credentialsMatcher 非常重要,因为在生产中数据库存的密码不会是一个明文的密码,会是一个加密后的密码,比对加密的密码也是通过credentialsMatcher 来进行比对

时间: 2024-10-18 07:51:51

Shiro-认证的相关文章

Apache Shiro 使用手册(二)Shiro 认证

认证就是验证用户身份的过程.在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法.最常见的"实体/凭证"组合便是"用户名/密码"组合. 一.Shiro认证过程 1.收集实体/凭据信息 Java代码   //Example using most common scenario of username/password pair: UsernamePasswordToken token = new Userna

JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权

shiro介绍 什么是shiro shiro是Apache的一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权.加密.会话管理等功能,组成了一个通用的安全认证框架.它可以实现如下的功能: 1.验证用户 2.对用户执行访问控制,如:判断用户是否具有角色admin,判断用户是否拥有访问的资源权限. 3.在任何环境下使用SessionAPI.例如C/S程序 4.可以使用多个用户数据源.例如一个是Oracle数据库,另外一个是MySQL数据库. 5.单点登录(SSO)功能

权限项目总结(三) shiro 认证

认证是shiro在使用过程中最开始的一个步骤,只有通过了认证才回有下面授权等操作.认证就是shiro获取当前 用户凭据并进行匹配的过程,最朴素的理解就是弄清楚当前用户的到底是谁的过程.这里也是针对在应用层面的总结,因为发现跟到shiro内部东西就很多了,容易迷失自己. 其实shiro认证过程简化的步骤非常简单 1.提交凭据 2.获取验证信息 3.验证凭据和验证信息是否一致 看一下详细的步骤 粗略的跟了一下shiro认证的流程,处理流程如下. 流程中省去了提交表单获取凭据的过程,也省去了在自定义r

【shiro】(4)---Shiro认证、授权案例讲解

Shiro认证.授权案例讲解 一.认证  1. 认证流程     2.用户密码已经加密.加盐的用户认证 (1)测试类 // 用户登陆和退出,这里我自定了一个realm(开发肯定需要自定义realm获取数据库密码和权限) @Test public void testCustomRealmMd5() { // 创建securityManager工厂,通过ini配置文件创建securityManager工厂 Factory<SecurityManager> factory = new IniSecu

shiro认证-SSM

shiro认证-SSM pom <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId>

shiro框架学习-2-springboot整合shiro及Shiro认证授权流程

1. 添加依赖 1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-web</artifactId> 4 </dependency> 5 <dependency> 6 <groupId>mysql</groupId> 7 <artifactId>mys

shiro认证

shiro权限认证: 具体的认证流程是这样的: 一般流程: 通过.ini的文件来初始化工厂,.ini的文件的好处是可以创建多个组,而.properties的文件只能创建一组. 系统默认有shiro.ini的文件,但是一般我们是自定义数据源Realm:来存放数据: 该类如下:这里采用了模拟数据库: package cn.itcast.shiro; import java.util.HashMap; import java.util.Map; import org.apache.shiro.auth

源码分析shiro认证授权流程

1. shiro介绍 Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能: 认证 - 用户身份识别,常被称为用户“登录”: 授权 - 访问控制: 密码加密 - 保护或隐藏数据防止被偷窥: 会话管理 - 每用户相关的时间敏感的状态. 对于任何一个应用程序,Shiro都可以提供全面的安全管理服务.并且相对于其他安全框架,Shiro要简单的多. 2. shiro源码概况 先要了解shiro的基本框架(见http://www.cnblogs.com/davi

Shiro认证时的密码比对

在前面一节<Shiro在Web环境下集成Spring的大致工作流程>的最后一步中提到由Shiro完整密码比对. 那么具体是怎么工作的? 1,既然shiro会把密码来进行比对,当然会调用 UserNamePasswordkToken 中的 getPassword() 方法了.在该方法中打上断点,往前跟踪一下即可. 2,开启debug模式,跟踪发现 org.apache.shiro.authc.credential.SimpleCredentialsMatcher 类进行密码的比对 3,继续跟踪,

Apache Shiro 认证、授权、加密和会话管理

官方解释 : Apache Shiro(日语"堡垒(Castle)"的意思)是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理功能,可为任何应用提供安全保障 - 从命令行应用.移动应用到大型网络及企业应用. Shiro为解决下列问题(我喜欢称它们为应用安全的四要素)提供了保护应用的API: 认证 - 用户身份识别,常被称为用户"登录": 授权 - 访问控制: 密码加密 - 保护或隐藏数据防止被偷窥: 会话管理 - 每用户相关的时间敏感的状态. Shi