博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Shiro入门实战【附源码】
阅读量:3947 次
发布时间:2019-05-24

本文共 16749 字,大约阅读时间需要 55 分钟。

文章目录

1. Shiro简介

写代码前可以简单了解一下 Shiro

2. Shiro 的认证流程

在这里插入图片描述

3. 编码实战

3.1 创建 SpringBoot 项目,pom.xml 依赖如下:

4.0.0
org.springframework.boot
spring-boot-starter-parent
1.5.16.RELEASE
org.example
shiro
1.0-SNAPSHOT
war
shiro
Demo project for shiro
1.8
org.projectlombok
lombok
1.18.12
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.1
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-tomcat
provided
org.apache.shiro
shiro-core
1.3.2
org.apache.shiro
shiro-spring
1.3.2
com.alibaba
druid
1.0.20
org.apache.commons
commons-lang3
3.4
org.springframework
spring-context-support
4.2.3.RELEASE
org.apache.tomcat.embed
tomcat-embed-jasper
javax.servlet
javax.servlet-api
javax.servlet
jstl
org.springframework.boot
spring-boot-maven-plugin

3.2 application.yml 配置如下:

# 数据库配置spring:  datasource:    type: com.alibaba.druid.pool.DruidDataSource    driver-class-name: com.mysql.jdbc.Driver    url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8    username: root    password: 123456  # jsp 配置 前缀/后缀  mvc:    view:      prefix: /pages/      suffix: .jsp# mybatis 配置mybatis:  mapper-locations: mappers/*.xml  type-aliases-package: org.main.entity

3.3 实体类创建

创建与数据库对应的实体类,主要有 User、Role、Permission 这三个实体类,代码如下:

package org.main.entity;import lombok.Data;import java.io.Serializable;/** * 角色权限类 * @Author: bai * @DateTime: 2020/6/25 9:21 */@Datapublic class Permission implements Serializable {
/** * 权限id */ private Integer pid; /** * 权限组名称 */ private String name; /** * 可访问的 url */ private String url;}
package org.main.entity;import lombok.Data;import java.io.Serializable;import java.util.HashSet;import java.util.Set;/** * 角色类 * @Author: bai * @DateTime: 2020/6/25 9:22 */@Datapublic class Role implements Serializable {
/** * 角色id */ private Integer rid; /** * 角色名称 */ private String rname; /** * 角色权限[单角色可能具备多种权限] */ private Set
permissions = new HashSet
(); /** * 角色属于哪个用户[单角色可能属于多个用户],[同时有多人具备同一种角色] */ private Set
users = new HashSet
();}
package org.main.entity;import lombok.Data;import java.io.Serializable;import java.util.HashSet;import java.util.Set;/** * 用户类 * @Author: bai * @DateTime: 2020/6/25 9:23 */@Datapublic class User implements Serializable {
/** * 用户id */ private Integer uid; /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 用户的角色[单用户可能具备多种角色] */ private Set
roles = new HashSet
();}

3.4 创建 mapper 接口

package org.main.mapper;import org.apache.ibatis.annotations.Param;import org.main.entity.User;/** * @Author: bai * @DateTime: 2020/6/25 9:29 */public interface UserMapper {
User findByUsername(@Param("username") String username);}

3.5 在主启动类上加 @MapperScan 注解扫描 mapper 的位置

package org.main;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.ComponentScan;/** * @Author: bai * @DateTime: 2020/6/25 9:30 */@SpringBootApplication@ComponentScan@MapperScan(basePackages = {
"org.main.mapper"})public class ShrioApplication {
public static void main(String[] args) {
SpringApplication.run(ShrioApplication.class, args); }}

3.6 创建 mapper.xml 文件,代码如下:

3.7 创建数据库 test,sql 语句如下:

-- 权限表--CREATE TABLE permission (  pid int(11) NOT NULL AUTO_INCREMENT,  name VARCHAR(255) NOT NULL DEFAULT '',  url VARCHAR(255) DEFAULT '',  PRIMARY KEY (pid)) ENGINE =InnoDB DEFAULT CHARSET = utf8;INSERT INTO permission VALUES ('1','add','');INSERT INTO permission VALUES ('2','delete','');INSERT INTO permission VALUES ('3','edit','');INSERT INTO permission VALUES ('4','query','');-- 用户表--CREATE TABLE user(uid int(11) NOT NULL AUTO_INCREMENT,username VARCHAR(255) NOT NULL DEFAULT '',password VARCHAR(255) NOT NULL DEFAULT '',PRIMARY KEY (uid)) ENGINE =InnoDB DEFAULT CHARSET=utf8;INSERT INTO user VALUES ('1','admin','123');INSERT INTO user VALUES ('2','demo','123');-- 角色表--CREATE TABLE role(rid int(11) NOT NULL AUTO_INCREMENT,rname VARCHAR(255) NOT NULL DEFAULT '',PRIMARY KEY (rid)) ENGINE =InnoDB DEFAULT CHARSET=utf8;INSERT INTO role VALUES ('1','admin');INSERT INTO role VALUES ('2','customer');-- 权限角色关系表--CREATE TABLE permission_role(  rid int(11) NOT NULL ,  pid int(11) NOT NULL ,  KEY idx_rid(rid),  KEY idx_pid(pid)) ENGINE = InnoDB DEFAULT CHARSET = utf8;INSERT INTO permission_role VALUES ('1','1');INSERT INTO permission_role VALUES ('1','2');INSERT INTO permission_role VALUES ('1','3');INSERT INTO permission_role VALUES ('1','4');INSERT INTO permission_role VALUES ('2','1');INSERT INTO permission_role VALUES ('2','4');-- 用户角色关系表--CREATE TABLE user_role(  uid int(11) NOT NULL ,  rid int(11) NOT NULL ,  KEY idx_uid(uid),  KEY idx_rid(rid)) ENGINE = InnoDB DEFAULT CHARSET = utf8;INSERT INTO user_role VALUES (1,1);INSERT INTO user_role VALUES (2,2);

3.8 创建 AuthRealm,实现 Shiro 框架的 AuthorizingRealm,代码如下:

package org.main.config;import org.apache.shiro.authc.*;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.main.entity.Permission;import org.main.entity.Role;import org.main.entity.User;import org.main.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.apache.commons.collections.CollectionUtils;import java.util.ArrayList;import java.util.List;import java.util.Set;/** * @Author: bai * @DateTime: 2020/6/25 9:41 */public class AuthRealm extends AuthorizingRealm {
@Autowired private UserService userService; //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.fromRealm(this.getClass().getName()).iterator().next(); List
permissionList = new ArrayList
(); List
roleNameList = new ArrayList
(); Set
roleSet = user.getRoles(); if (CollectionUtils.isNotEmpty(roleSet)) {
for (Role role : roleSet) {
roleNameList.add(role.getRname()); Set
permissionSet = role.getPermissions(); if (CollectionUtils.isNotEmpty(permissionSet)) { for (Permission permission : permissionSet) { permissionList.add(permission.getName()); } } } } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermissions(permissionList); info.addRoles(roleNameList); return info; } // 认证登陆 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken; String username = usernamePasswordToken.getUsername(); User user = userService.findByUsername(username); return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName()); }}

3.9 创建 Shiro 的配置类:

package org.main.config;import org.apache.shiro.cache.MemoryConstrainedCacheManager;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.util.LinkedHashMap;/** * Shiro 配置类 * * @Author: bai * @DateTime: 2020/6/25 9:52 */@Configurationpublic class ShiroConfiguration {
@Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(manager); bean.setLoginUrl("/login"); bean.setSuccessUrl("/index"); bean.setUnauthorizedUrl("/unauthorized"); LinkedHashMap
filterChainDefinitionMap = new LinkedHashMap
(); // authc 表示只有登陆后才有权限访问,anon 表示没有登陆也有权限访问 filterChainDefinitionMap.put("/index", "authc"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/loginUser", "anon"); // admin 接口指允许admin角色访问 filterChainDefinitionMap.put("/admin", "roles[admin]"); filterChainDefinitionMap.put("/edit", "perms[edit]"); // 开放druid所有请求,可以访问druid监控 filterChainDefinitionMap.put("/**", "user"); bean.setFilterChainDefinitionMap(filterChainDefinitionMap); return bean; } @Bean("securityManager") public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(authRealm); return manager; } @Bean("authRealm") public AuthRealm authRealm(@Qualifier("credentialMatcher") CredentialMatcher credentialMatcher) {
AuthRealm authRealm = new AuthRealm(); // 使用缓存 authRealm.setCacheManager(new MemoryConstrainedCacheManager()); authRealm.setCredentialsMatcher(credentialMatcher); return authRealm; } @Bean("credentialMatcher") public CredentialMatcher credentialMatcher() {
return new CredentialMatcher(); } /** * 以下的两个方法是设置 shiro 与 spring 之间的关联 * * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; }}

3.10 创建 CredentialMatcher,做密码比较的规则验证:

package org.main.config;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;/** * 密码校验规则 * * @Author: bai * @DateTime: 2020/6/25 10:03 */public class CredentialMatcher extends SimpleCredentialsMatcher {
@Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String password = new String(usernamePasswordToken.getPassword()); String dbPassword = (String) info.getCredentials(); return this.equals(password, dbPassword); }}

3.11 Service 层实现:

package org.main.service;import org.main.entity.User;import org.main.mapper.UserMapper;import org.springframework.stereotype.Service;import javax.annotation.Resource;/** * @Author: bai * @DateTime: 2020/6/25 9:42 */@Servicepublic class UserService {
@Resource private UserMapper userMapper; public User findByUsername(String username) {
return userMapper.findByUsername(username); }}

3.12 Controller 层实现:

package org.main.controller;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.main.entity.User;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpSession;/** * @Author: bai * @DateTime: 2020/6/25 10:10 */@RestControllerpublic class UserController {
@GetMapping(value = "/login") public String login() {
return "login"; } /** * 两个case * 第一个是只有登陆后才能访问相关的接口,没有登陆是不允许访问相关的接口,例如admin接口 * 第二个是某些接口只能被某些角色访问 * @return */ @GetMapping(value = "/admin") public String admin() {
return "admin success"; } @GetMapping(value = "/logout") public String logout() {
Subject subject = SecurityUtils.getSubject(); if (null != subject) {
subject.logout(); } return "login"; } @GetMapping(value = "/index") public String index() {
return "index"; } @GetMapping(value = "/edit") public String edit() {
return "edit success"; } @GetMapping(value = "/unauthorized") public String unauthorized() {
return "unauthorized"; } @PostMapping(value = "/loginUser") public String loginUser(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password, HttpSession session) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); try {
subject.login(token); User user = (User) subject.getPrincipal(); session.setAttribute("user", user); return "index"; } catch (Exception e) {
e.printStackTrace(); return "login"; } }}

3.13 jsp 页面实现:

index.jsp

<%--  Created by IntelliJ IDEA.  User: bai  Date: 2020/6/25  Time: 10:20  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %>    Home    

欢迎登陆, ${user.username}

login.jsp

<%--  Created by IntelliJ IDEA.  User: bai  Date: 2020/6/25  Time: 10:21  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %>    Login    

欢迎登陆

unauthorized.jsp

<%--  Created by IntelliJ IDEA.  User: bai  Date: 2020/6/25  Time: 10:22  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %>    Unauthorized    

Unauthorized!

完整的项目结构

在这里插入图片描述

4. 项目源码地址:

转载地址:http://ovqwi.baihongyu.com/

你可能感兴趣的文章
Python3中利用Urllib进行表单数据提交(Get,Post)
查看>>
Python开发之扩展库的安装指南及Suds(Webservice)的使用简介
查看>>
软件项目管理一点分享
查看>>
iphone程序打包ipa格式
查看>>
Ios开发之Apns功能介绍(应用程序通知)及PHP/Python代码
查看>>
iphone开发的几个Apple官方中文教程地址
查看>>
Algorithms: Kruskal's algorithm and Prim's algorithm for Minimum-spanning-tree
查看>>
Algorithm : Dijkstra's algorithm and Bellmon-Ford Paths algorithm
查看>>
Algorithm: k-nearest neighbors and decison boundary(Cross Validation)
查看>>
Algorithm: Principle Component Analysis for High Dimension Reduction Data
查看>>
Naive Bayesian for Text Classification (MLE, Gaussian Naive Bayesian)
查看>>
Algorithm: Decision Tree, Entropy, Information Gain and Continues features
查看>>
FastDFS 架构分析
查看>>
Windows 应用生成MiniDump文件的方法笔记
查看>>
安装FastDFS单机版环境
查看>>
动态规划-背包问题
查看>>
Windows10 + Nodejs调用C++语言Dll
查看>>
CSAPP - 一个简单的Shell
查看>>
《算法4》 Windows/Mac环境下使用Visual Studio Code和Orcale JDK1.8开发环境搭建
查看>>
精心整理很实用的前端笔记,看完你就在css上有很深的造诣了!!!
查看>>