引入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>
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"; } }
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; } }
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>
来源:https://www.cnblogs.com/realshijing/p/8299245.html