springmvc+shiro驗證嵌入方法介紹,學習筆記(一)
1.新增shiro框架包
<!--shiro許可權管理--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency>
2.在web.xml中新增過濾器,意思是url被該過濾器攔截做許可權驗證,驗證通過才給到controller。
<!-- 配置 Shiro 的 Filter --> <filter> <description>shiro 許可權攔截</description> <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>
3.配置shiro的applicationContext 新建一個recources/applicationContext-shiro.xml (注意按自己的mvc配置命名)
<?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:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 啟用shrio授權註解攔截方式 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 裝配 securityManager --> <property name="securityManager" ref="securityManager"/> <!-- 配置登陸頁面 --> <property name="loginUrl" value="/login.html"/> <!-- 登陸成功後的一面 --> <property name="successUrl" value="/success.html"/> <property name="unauthorizedUrl" value="/403.html"/> <!-- 具體配置需要攔截哪些 URL, 以及訪問對應的 URL 時使用 Shiro 的什麼 Filter 進行攔截. --> <property name="filterChainDefinitions"> <value> /login.html = anon /subLogin = anon /roles = roles[admin] /testPerms = roles[admin],perms[ordertable:add] /** = roles["admin"] </value> </property> </bean> <!-- 配置進行授權和認證的 Realm --> <bean id="myRealm" class="cn.longteng.shiro.realm.ShiroDbRealm"> </bean> <!-- 配置 Shiro 的 SecurityManager Bean. --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myRealm"/> </bean> </beans>
4.自定義Realm,realm時shiro驗證身份和許可權的邏輯控制器,裡面理論上是放賬號和許可權的資料庫查詢和判斷邏輯 新建一個ShiroDbRealm繼承AuthorizingRealm,會要求你重寫兩個方法 許可權授權---doGetAuthorizationInfo(PrincipalCollection principals) 賬號認證---doGetAuthenticationInfo(AuthenticationToken token)
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.HashSet;
import java.util.Set;
/**
* @Description:
* @Author longteng
* @Version v2.0
* @Date: 2018/9/6
* @since:
*/
public class ShiroDbRealm extends AuthorizingRealm {
//授權
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
{
System.out.println("資料庫進行許可權認證");
//通過傳過來的資訊中,獲取使用者名稱
String userName = (String) principals.getPrimaryPrincipal();
//從資料庫獲取角色與許可權
Set<String> setsR = new HashSet<String>();
Set<String> setsP = new HashSet<String>();
getRolesAndPermissionOnDB(userName,setsR,setsP);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(setsR);;
simpleAuthorizationInfo.setStringPermissions(setsP);
return simpleAuthorizationInfo;
}
//認證
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
System.out.println("資料庫進行賬號認證");
//通過傳過來的資訊中,獲取使用者名稱
String userName = (String) token.getPrincipal();
//通過使用者名稱到資料庫中獲取憑證
String password =getPassOnDB(userName);
if (password == null)
{
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, password, "CustomRealm");
return authenticationInfo;
}
private String getPassOnDB(final String username)
{
//從資料庫裡查出密碼是多少
//………………
return "123456";//假設查出來是123456
}
private void getRolesAndPermissionOnDB(String username, Set<String> setsR, Set<String> setsP)
{
//從資料庫裡查出該賬號的授權資料
//…………
//假設查出來如下
setsR.add("admin"); //admin角色
setsP.add("ordertable:add");//許可權
setsP.add("ordertable:del");
}
}
5.新增以下介個xml用作登陸驗證與提示
403.html:
{"ret":"fail","msg":"未經身份驗證"}
Success.html:
{"ret":"success","msg":"登陸成功"}
Login.html:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<table>登陸</table>
</head>
<body>
<form action="subLogin" method="post">
使用者名稱:<input type="text" name="username"><br>
密碼:<input type="text" name="password" ><br>
<input type="submit" name="登陸">
</form>
</body>
</html>
Logout.html:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<table>是否登出:</table>
</head>
<body>
<form action="subLogout" method="post">
<input type="submit" name="登出">
</form>
</body>
</html>
6.編輯subLogin介面和sunLogout介面 (1)建立類UserController編寫介面
import cn.longteng.web.comtroller.entity.User;
import cn.longteng.web.utils.RetMsg;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/**
* @Description:
* @Author longteng
* @Version v2.0
* @Date: 2018/9/6
* @since:
*/
@Controller
public class UserController
{
@RequestMapping(value = "/subLogin", method = RequestMethod.POST, produces="text/html; charset=UTF-8")
@ResponseBody
public String subLogin(User user)
{
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
try
{
token.setRememberMe(user.isRemenmberMe());
subject.login(token);
}
catch (AuthenticationException e)
{
return RetMsg.FL(e.toString());
}
return RetMsg.SU("登陸成功");
}
@RequestMapping(value = "/subLogout", method = RequestMethod.POST, produces="text/html; charset=UTF-8")
@ResponseBody
public String subLogout()
{
Subject subject = SecurityUtils.getSubject();
try
{
subject.logout();
}
catch (AuthenticationException e)
{
return RetMsg.FL(e.toString());
}
return RetMsg.SU("登出成功");
}
}
(2)建立類User類用於引數接收。
public class User
{
private String username;
private String password;
private boolean remenmberMe;
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;
}
public boolean isRemenmberMe() {
return remenmberMe;
}
public void setRemenmberMe(boolean remenmberMe) {
this.remenmberMe = remenmberMe;
}
}
7.好了,我們可以開始我們的介面開發了。配合前面的配置
8.我們來測試以下成果 (1)執行起來後你會發現訪問任何介面都會跳轉到login.html
(2)只有當我們輸入賬號密碼登陸後,接口才能正常呼叫
(3)介面就可以使用了
9.題外話,如果你做前後端分離的應用,例如為Android的app提供介面,我們怎麼進行驗證呢? (1)首先推薦安裝一個postman測試工具 (2)按以下配置設定介面
(3)呼叫成功後檢視cookie
(4)配置帶該cookie的介面
10.Ok大功告成 當然了,還有MD5密碼加密加鹽,還有自定義cookie,還有記住驗證,還有驗證有效期,還有redis的快取,還有賬號比對的優化不要去查那麼多次資料。我在後面的的文章給大家介紹。該程式碼只是shiro結合mvc的原型。還有很多優化和技巧要我們去挖掘,筆者也是才寫完一個功能架構,寫出這篇文章,大家互相學習,不喜勿噴。(以上程式碼說明也許有部分遺漏或者錯誤,如有疑問請下載完整程式碼)。建議擁有springmvc基礎再學習該知識