基于Shiro的用户认证
1.创建web工程
由于IDEA的web工程不会创建java和resouces目录,所以需要手动创建
2.在pom.xml导入相关坐标
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>shiro_spring_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
</dependencies>
</project>
3.修改WEB-INF下的web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--spring核心监听器,默认加载WEB-INF目录下的applicationContext.xml-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext*.xml</param-value>
</context-param>
<!--springMVC-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!--配置 spring 中提供的 shiro 过滤器(一当十的过滤器)-->
<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>
</web-app>
4.在resouces下增加目录spring下增加配置文件springmvc.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" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描注解-->
<context:component-scan base-package="com.demo"/>
<!-- 注解驱动-->
<mvc:annotation-driven/>
</beans>
5.在spring下增加shiro的核心配置文件applicationContext-shiro.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">
<!-- 配置Spring整合shiro -->
<!-- 配置安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 自己编写一个realm域对象 -->
<property name="realm" ref="authRealm"/>
</bean>
<!-- 编写realm类 -->
<bean id="authRealm" class="com.demo.shiro.AuthRealm">
<!-- 注入密码比较器对象 -->
<property name="credentialsMatcher" ref="customCredentialsMatcher"/>
</bean>
<!-- 密码比较器类 -->
<bean id="customCredentialsMatcher" class="com.demo.shiro.CustomCredentialsMatcher"/>
<!-- Spring框架需要整合shiro安全框架 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 注入安全管理器 -->
<property name="securityManager" ref="securityManager"/>
<!-- 登录页面 -->
<property name="loginUrl" value="/login.html"/>
<!-- 认证成功了,跳转的页面-->
<property name="successUrl" value="/index.jsp"/>
<!-- 没有权限的跳转页面 -->
<property name="unauthorizedUrl" value="/error.html"/>
<!-- 定义访问的规则 -->
<property name="filterChainDefinitions">
<!-- /**代表下面的多级目录也过滤 -->
<value>
/login.do=anon
/login.html = anon
/error.html = anon
/** = authc
/*.* = authc
</value>
</property>
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 生成代理,通过代理进行控制 -->
<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>
</beans>
6.最终工程目录
7.添加相关代码
UserController.java
package com.demo.controller;
import com.demo.domain.User;
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;
@Controller
public class UserController {
//登录
@RequestMapping("/login")
public String login(String username, String password) {
try {
//1.得到subject对象
Subject subject = SecurityUtils.getSubject();
//2.封装用户数据
AuthenticationToken token = new UsernamePasswordToken(username, password);
//3.实现登录操作
subject.login(token);
//4.登录成功后,可以从shiro取出用户信息
User user = (User) subject.getPrincipal();
return "redirect:/index.jsp";
} catch (AuthenticationException e) {
e.printStackTrace();
return "redirect:/error.html";
}
}
//退出
@RequestMapping("/logout")
public String logout() {
SecurityUtils.getSubject().logout();
return "redirect:/login.html";
}
}
User.java
package com.demo.domain;
public class User {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
自定义认证域 AuthRealm.java
package com.demo.shiro;
import com.demo.domain.User;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
//自定义realm域
public class AuthRealm extends AuthorizingRealm {
//授权:赋予用户角色
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//认证:验证登录时用户输入的账号和密码
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//强转拿到存有用户输入的账号密码的对象
UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
//获取账号
String username = upToken.getUsername();
//模拟安全认证对象(一般根据username去数据库查,这里只做模拟)
// User user = userService.findUserByUsername(username);
User user = null;
if ("admin".equalsIgnoreCase(username)) {
user = new User("admin", "admin");
}
//判断对象在数据库中是否存在
if (user != null) {
//第一个参数:安全数据(user对象)
//第二个参数:密码(数据库密码)
//第三个参数:当前调用realm域的名称(类名即可)
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
return info;
}
return null;
}
}
自定义密码比较器 CustomCredentialsMatcher.java
package com.demo.shiro;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
//自定义密码比较器
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {
/**
* @param token 用户界面输入的账号和密码
* @param info 安全数据:用户对象user
* @return
*/
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
//向下强转获得实现类
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
//获取用户输入的密码
String inputPwd = new String(upToken.getPassword());
//获取认证类传入的安全认证对象密码
String dbPwd = info.getCredentials().toString();
//返回判断密码结果
return dbPwd.equals(inputPwd);
}
}
8.添加登录页面login.html和失败error.html
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form action="/login.do" method="post">
<table align="center">
<tr>
<td>账号:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td colspan="2">
<input style="width: 100%" type="submit" value="登录">
</td>
</tr>
</table>
</form>
</body>
</html>
error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆失败</title>
</head>
<body>
<h1>账号或密码错误!</h1>
<a href="/login.html"><h3>回到登录页</h3></a>
</body>
</html>
9.启动服务和测试
配置tomcat可以参考我的配置tomcat博客,这里就不再赘述了,
启动之后弹出页面:
第一次测试,输入正确账号admin,密码admin
第二次测试,输入错误账号admin111,密码admin111
点击登录之后
第三次测试,输入正确账号admin,错误密码admin111
至此,配置shiro和springmvc整合完成了,如果遇到问题可以私我,也可以发表评论。
谢谢观看,如有不足,还请指正。