Apache Shiro 快速入門教程,shiro 基礎教程
第一部分 什麼是Apache Shiro
1、什麼是 apache shiro :
Apache Shiro是一個功能強大且易於使用的Java安全框架,提供了認證,授權,加密,和會話管理
如同 Spring security 一樣都是是一個許可權安全框架,但是與Spring Security相比,在於他使用了和比較簡潔易懂的認證和授權方式。
2、Apache Shiro 的三大核心元件:
1、Subject :當前使用者的操作
2、SecurityManager:用於管理所有的Subject
3、Realms:用於進行許可權資訊的驗證
Subject:即當前使用者,在許可權管理的應用程式裡往往需要知道誰能夠操作什麼,誰擁有操作該程式的權利,shiro中則需要通過Subject來提供基礎的當前使用者資訊,Subject 不僅僅代表某個使用者,也可以是第三方程式、後臺帳戶(Daemon Account)或其他類似事物。
SecurityManager:即所有Subject的管理者,這是Shiro框架的核心元件,可以把他看做是一個Shiro框架的全域性管理元件,用於排程各種Shiro框架的服務。
Realms:Realms則是使用者的資訊認證器和使用者的許可權人證器,我們需要自己來實現Realms來自定義的管理我們自己系統內部的許可權規則。
3、Authentication 和 Authorization
在shiro的使用者許可權認證過程中其通過兩個方法來實現:
1、Authentication:是驗證使用者身份的過程。
2、Authorization:是授權訪問控制,用於對使用者進行的操作進行人證授權,證明該使用者是否允許進行當前操作,如訪問某個連結,某個資原始檔等。
4、其他元件:
除了以上幾個元件外,Shiro還有幾個其他元件:
1、SessionManager :Shiro為任何應用提供了一個會話程式設計正規化。
2、CacheManager :對Shiro的其他元件提供快取支援。
5、Shiro 完整架構圖:
圖片轉自:http://kdboy.iteye.com/blog/1154644
第二部分 Apache Shiro 整合Spring的Web程式構建
1、準備工具:
持久層框架:Hibernate4 這邊我使用了Hibernate來對資料持久層進行操作
控制顯示層框架:SpringMVC 這邊我使用了SpringMVC實際開發中也可以是其他框架
資料庫:MySql
準備好所需要的jar放到專案中。
2、建立資料庫:
首先需要四張表,分別為 user(使用者)、role(角色)、permission(許可權)、userRole(使用者角色關係表)
這邊分別建立四張表的實體類,通過Hiberante的hibernate.hbm2ddl.auto屬性的update 來自動生成資料表結構。
/***
* 使用者表
*
* @author Swinglife
*
*/
@Table(name = "t_user")
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
/** 使用者名稱 **/
String username;
/** 密碼 **/
String password;
/** 是否刪除 **/
Integer isDelete;
/** 建立時間 **/
Date createDate;
//多對多使用者許可權表
@OneToMany(mappedBy = "user",cascade=CascadeType.ALL)
List<UserRole> userRoles;
省略get set….
}
/****
* 角色表
*
* @author Swinglife
*
*/
@Entity
@Table(name = "t_role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
/**角色名**/
String name;
/**角色說明**/
String description;
}
/****
* 許可權表
*
* @author Swinglife
*
*/
@Entity
@Table(name = "t_permission")
public class Permission {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
/**token**/
String token;
/**資源url**/
String url;
/**許可權說明**/
String description;
/**所屬角色編號**/
Integer roleId;
}
/***
* 使用者角色表
*
* @author Swinglife
*
*/
@Entity
@Table(name = "t_user_role")
public class UserRole {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "userId", unique = true)
User user;
@ManyToOne
@JoinColumn(name = "roleId", unique = true)
Role role;
}
3、編寫操作使用者業務的Service:
@Service
public class AccountService {
/****
* 通過使用者名稱獲取使用者物件
*
* @param username
* @return
*/
public User getUserByUserName(String username) {
User user = (User) dao.findObjectByHQL("FROM User WHERE username = ?", new Object[] { username });
return user;
}
/***
* 通過使用者名稱獲取許可權資源
*
* @param username
* @return
*/
public List<String> getPermissionsByUserName(String username) {
System.out.println("呼叫");
User user = getUserByUserName(username);
if (user == null) {
return null;
}
List<String> list = new ArrayList<String>();
// System.out.println(user.getUserRoles().get(0).get);
for (UserRole userRole : user.getUserRoles()) {
Role role = userRole.getRole();
List<Permission> permissions = dao.findAllByHQL("FROM Permission WHERE roleId = ?", new Object[] { role.getId() });
for (Permission p : permissions) {
list.add(p.getUrl());
}
}
return list;
}
// 公共的資料庫訪問介面
// 這裡省略BaseDao dao的編寫
@Autowired
private BaseDao dao;
}
4、編寫shiro元件自定義Realm:
package org.swinglife.shiro;
import java.util.List;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.swinglife.model.User;
import org.swinglife.service.AccountService;
/****
* 自定義Realm
*
* @author Swinglife
*
*/
public class MyShiroRealm extends AuthorizingRealm {
/***
* 獲取授權資訊
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
//根據自己系統規則的需要編寫獲取授權資訊,這裡為了快速入門只獲取了使用者對應角色的資源url資訊
String username = (String) pc.fromRealm(getName()).iterator().next();
if (username != null) {
List<String> pers = accountService.getPermissionsByUserName(username);
if (pers != null && !pers.isEmpty()) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
for (String each : pers) {
//將許可權資源新增到使用者資訊中
info.addStringPermission(each);
}
return info;
}
}
return null;
}
/***
* 獲取認證資訊
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) at;
// 通過表單接收的使用者名稱
String username = token.getUsername();
if (username != null && !"".equals(username)) {
User user = accountService.getUserByUserName(username);
if (user != null) {
return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
}
}
return null;
}
/**使用者的業務類**/
private AccountService accountService;
public AccountService getAccountService() {
return accountService;
}
public void setAccountService(AccountService accountService) {
this.accountService = accountService;
}
}
上述類繼承了Shiro的AuthorizingRealm類 實現了AuthorizationInfo和AuthenticationInfo兩個方法,用於獲取使用者許可權和認證使用者登入資訊
5、編寫LoginController:
package org.swinglife.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.portlet.ModelAndView;
import org.swinglife.model.User;
import org.swinglife.service.AccountService;
/****
* 使用者登入Controller
*
* @author Swinglife
*
*/
@Controller
public class LoginController {
/***
* 跳轉到登入頁面
*
* @return
*/
@RequestMapping(value = "toLogin")
public String toLogin() {
// 跳轉到/page/login.jsp頁面
return "login";
}
/***
* 實現使用者登入
*
* @param username
* @param password
* @return
*/
@RequestMapping(value = "login")
public ModelAndView Login(String username, String password) {
ModelAndView mav = new ModelAndView();
User user = accountService.getUserByUserName(username);
if (user == null) {
mav.setView("toLogin");
mav.addObject("msg", "使用者不存在");
return mav;
}
if (!user.getPassword().equals(password)) {
mav.setView("toLogin");
mav.addObject("msg", "賬號密碼錯誤");
return mav;
}
SecurityUtils.getSecurityManager().logout(SecurityUtils.getSubject());
// 登入後存放進shiro token
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
Subject subject = SecurityUtils.getSubject();
subject.login(token);
// 登入成功後會跳轉到successUrl配置的連結,不用管下面返回的連結。
mav.setView("redirect:/home");
return mav;
}
// 處理使用者業務類
@Autowired
private AccountService accountService;
}
6、編寫資訊認證成功後的跳轉頁面:
package org.swinglife.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("home")
public String index() {
System.out.println("登入成功");
return "home";
}
}
7、Shiro的配置檔案.xml
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/toLogin" />
<property name="successUrl" value="/home" />
<property name="unauthorizedUrl" value="/403" />
<property name="filterChainDefinitions">
<value>
/toLogin = authc <!-- authc 表示需要認證才能訪問的頁面 -->
/home = authc, perms[/home] <!-- perms 表示需要該許可權才能訪問的頁面 -->
</value>
</property>
</bean>
<bean id="myShiroRealm" class="org.swinglife.shiro.MyShiroRealm">
<property name="accountService" ref="accountService" />
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myShiroRealm"></property>
</bean>
<bean id="accountService" class="org.swinglife.service.AccountService"></bean>
<!-- <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="cacheManager" /> </bean> -->
loginUrl 用於配置登陸頁
successUrl 用於配置登入成功後返回的頁面,不過該引數只會在當登入頁面中並沒有任何返回頁面時才會生效,否則會跳轉到登入Controller中的指定頁面。
unauthorizedUrl 用於配置沒有許可權訪問頁面時跳轉的頁面
filterChainDefinitions:apache shiro通過filterChainDefinitions引數來分配連結的過濾,資源過濾有常用的以下幾個引數:
1、authc 表示需要認證的連結
2、perms[/url] 表示該連結需要擁有對應的資源/許可權才能訪問
3、roles[admin] 表示需要對應的角色才能訪問
4、perms[admin:url] 表示需要對應角色的資源才能訪問
8、登陸頁login.jsp
<body>
<h1>user login</h1>
<form action="login" method="post">
username:<input type="text" name="username"><p>
password:<input type="password" name="password">
<p>
${msg }
<input type="submit" value="submit">
</form>
</body>
9、執行程式
在資料庫中新增一條使用者、角色、以及許可權資料,並且在關聯表中新增一條關聯資料:
在瀏覽器中訪問: home頁面 就會跳轉到登入頁面:
最後輸入 賬號密碼 就會跳轉到登入成功頁面。
shiro jar:http://download.csdn.net/detail/swingpyzf/8766673
專案原始碼:github:https://github.com/swinglife/shiro_ex
因為工作的原因寫部落格和教程的時間越來越少了,所以今後的部落格儘量簡短明瞭,以實踐使用為主,
同時也歡迎大家關注我的個人公眾號來提相關問題,我會力所能及的回答。
相關文章
- Shiro 教程
- shiro教程(2): shiro介紹
- Oracle學習快速入門基礎教程Oracle
- Shiro系列教程之一Shiro簡介
- Shiro入門這篇就夠了【Shiro的基礎知識、回顧URL攔截】
- [翻譯-Shiro]-Apache Shiro 簡介Apache
- [翻譯-Shiro]-Apache Shiro 框架解析Apache框架
- 最簡明的Shiro教程
- SQLite基礎入門教程SQLite
- shiro教程(1):基於url許可權管理
- [翻譯-Shiro]-整合Apache Shiro到基於Spring的應用ApacheSpring
- [翻譯-Shiro]-Apache Shiro Java認證指南ApacheJava
- [翻譯-Shiro]-Apache Shiro Java 授權指南ApacheJava
- [翻譯-Shiro]-Apache Shiro Java註解列表ApacheJava
- Shiro安全框架【快速入門】就這一篇!框架
- Spring Boot 2.x基礎教程:快速入門Spring Boot
- Apache Flume 入門教程Apache
- [翻譯-Shiro]-10分鐘教會你Apache ShiroApache
- shiro入門學習--授權(Authorization)|築基初期
- [翻譯-Shiro]-Apache Shiro JSP/GSP標籤庫ApacheJS
- shiro入門知識介紹
- Shiro和Spring MVC、Mybatis整合教程SpringMVCMyBatis
- Apache Hadoop 入門教程ApacheHadoop
- Arduino基礎入門套件教程PDFUI套件
- Python Flask基礎教程(入門)PythonFlask
- ROS基礎入門——實操教程ROS
- Materialize快速入門教程
- latex快速入門教程
- ERWin建模基礎教程(非常好的入門教程)
- org.apache.shiro.authc.UsernamePasswordTokenApache
- web開發實戰教程:Apache Shiro在web專案中的應用WebApache
- 2020年Python基礎教程,Python快速入門教程(非常詳細)Python
- Apache Kafka教程--Kafka新手入門ApacheKafka
- Apache Commons IO入門教程Apache
- Python入門基礎教程(兒童版) [分享一本入門級教程]Python
- Nestjs入門教程【一】基礎概念JS
- Android入門教程 | Fragment 基礎概念AndroidFragment
- Python Django基礎教程(一)(入門)PythonDjango