Shiro之学习笔记(六)

Shiro整合SpringMVC在Web环境下实现登录认证

注:shiro的JavaEE环境搭建可以参考Shiro学习笔记(五):https://blog.youkuaiyun.com/weixin_41178230/article/details/82873443

Web环境下实现认证的基本流程:
1、jsp页面:包含用户信息,并封装到form表单中;
2、Spring MVC控制器:处理用户请求:
   - 获取用户的登录信息
   
   - shiro API来完成用户认证
    1)获取Subject类型的实例
    2)判断用户是否已经登录
    3)使用UsernamePasswordToken对象来封装用户名和密码
    4)使用Subject中的login(token)方法
    5)Realm:从数据库中获取安全数据
       - 将token的类型转换为UsernamePasswordToken
       - 从转换好的对象中获取用户名即可
       - 查询数据库,从数据库中查询是否存在相对应的用户名和密码
       - 如果查询到了,就封装结果,返回给我们的调用
       - 如果没有查询到,就抛出一个异常

springmvc-config.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:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.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">
    <!-- 配置包扫描器,扫描@Controller注解的类 -->
   	<context:component-scan base-package="com.shiro.controller" />
   	<!-- 加载注解驱动 -->
   	<mvc:annotation-driven />
   	<!-- 配置视图解析器 -->
   	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
   	    <property name="prefix" value="/" />
   	    <property name="suffix" value=".jsp" />
   	</bean>
    <!-- 开启aop,对类代理 -->
	<aop:config proxy-target-class="true"></aop:config>
	
</beans>

  login.jsp(包含用户信息,并封装到form表单中):

<%@ 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>
	<form action="login.action" method="post">
		username:<input type="text" name="username" />
		<br />
		password:<input type="password" name="password" />
		<br />
		<input type="submit" value="登录" />
	</form>
</body>
</html>

配置applicationContext.xml中的请求拦截路径:

LoginController.java:

package com.shiro.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
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
public class LoginController {
	
	@RequestMapping("/login.action")
    public String Login(@RequestParam("username") String username,@RequestParam("password") String password) {
    	
    	//获取Subject类型的实例
		System.out.println(username+"--------"+password);
    	Subject currentUser = SecurityUtils.getSubject();
    	//判断用户是否已经登录
    	if(currentUser.isAuthenticated()==false) {
    		//使用UsernamePasswordToken对象来封装用户名和密码
    		UsernamePasswordToken token = new UsernamePasswordToken(username,password);
    		//使用Subject中的login(token)方法
    		try{
    			currentUser.login(token);
    			System.out.println("登录验证");
    		}catch(AuthenticationException e) {
    			return "error";
    		}
    	}
    	
    	return "index";
    }
}

index.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>
	<p>Index Page.</p>
	<a href="logout">LOGOUT</a><!--点击按钮注销用户并退出 -->
</body>
</html>

error.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>
    <h3>Error Page.</h3>
</body>
</html>

ShiroRealm.java

package com.shiro.realm;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

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

//Realm:从数据库中获取并处理安全数据
public class ShiroRealm extends AuthenticatingRealm {
    
	/*
	 * 可以使用AuthenticationInfo接口中的SimpleAuthenticationInfo实现类来封装正确的用户名和密码
	 * 
	 * doGetAuthenticationInfo方法:获取认证信息,如果数据库中没有数据,就返回null;反之,则返回指定的类型的对象
	 * 
	 * AuthenticationToken token:就是我们要认证的token
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		/*
		 * 将token的类型转换为UsernamePasswordToken 
		 * 从转换好的对象中获取用户名即可
		 * 查询数据库,从数据库中查询是否存在相对应的用户名和密码
		 * 如果查询到了,就封装结果,返回给我们的调用
		 * 如果没有查询到,就抛出一个异常
		 */
		SimpleAuthenticationInfo info = null;
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		String userName = upToken.getUsername();
		
		//使用jdbc原生的API来从数据库中查询数据
		try {
			//获取驱动
			Class.forName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://localhost:3306/test";
			String username = "root";
			String password = "123";
			Connection con = DriverManager.getConnection(url, username, password);
			PreparedStatement ps = con.prepareStatement("select * from sec_user where user_name=?");
			ps.setString(1, userName);
			
			ResultSet rs = ps.executeQuery();
			
			if(rs.next()) {
				Object principal = userName;
				Object credentials = rs.getString(3);
				String realmName = this.getName();
				info = new SimpleAuthenticationInfo(principal, credentials, realmName);
			}else {
				throw new AuthenticationException();
			}
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return info;
	}

	

}

创建数据表并插入数据:

CREATE TABLE `sec_user` (
  `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_name` varchar(64) COLLATE utf8_bin DEFAULT NULL,
  `password` varchar(128) COLLATE utf8_bin DEFAULT NULL,
  `created_time` datetime DEFAULT NULL,
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

insert into sec_user(user_name,password) values ('tom','123456');
insert into sec_user(user_name,password) values ('jim','123456');

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值