Shiro之學習筆記(六)
阿新 • • 發佈:2018-12-12
Shiro整合SpringMVC在Web環境下實現登入認證
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');