
Authentication(认证), Authorization(授权), Session Management(会话管理), Cryptography(加密)被 Shiro 框架的开发团队称之为应用安全的四大基石。
还有其他的功能来支持和加强这些不同应用环境下安全领域的关注点。特别是对以下的功能支持:


<!-- Subject 用户-->
<!-- SecurityManager 管理所有用户-->
<!-- Realm 连接数据-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
</body>
</html>
package com.xiaozhi.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
@Controller
public class MyController {
@RequestMapping({"/","index"})
public String toIndex(Model model){
model.addAttribute("msg","hello,shiro");
return "index";
}
}
package com.xiaozhi.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//3
//shiroFileterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(defaultWebSecurityManager);
return bean;
}
//2
//DafaultWebSecurityManager
@Bean(name = "SecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联UserRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1
//创建 realm 对象,需要定义类
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
//整合shiroDialect:用来整合shiro thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
package com.xiaozhi.config;
import com.xiaozhi.mapper.UserMapper;
import com.xiaozhi.pojo.User;
import org.apache.shiro.SecurityUtils;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
//自定义的 UserRealm extends AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=》授权doGetAuthorizationInfo");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了=》授权doGetAuthenticationInfo");
// return null;
}
}
在templates下加入login.html并创建文件夹user,并创建update.html、add.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录页</h1>
<hr>
<form method="post" action="/login" >
<p th:text="${msg}"></p>
<label><input name="username" type="text" placeholder="用户名"></label>
<label><input name="password" type="text" placeholder="密码"></label>
<label><input type="submit" value="登录"></label>
</form>
<hr>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2 th:text="${msg}"></h2>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2 th:text="${msg}"></h2>
</body>
</html>
controller下加入
package com.xiaozhi.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
/**
* @Author Administrator
* @Date 2021/6/18 22:06
* @Version 1.0
*/
@Controller
public class MyController {
@RequestMapping({"/","index"})
public String toIndex(Model model){
model.addAttribute("msg","hello,shiro");
return "index";
}
@RequestMapping({"/user/add"})
public String add(Model model){
model.addAttribute("msg","hello,add");
return "user/add";
}
@RequestMapping({"/user/update"})
public String update(Model model){
model.addAttribute("msg","hello,update");
return "user/update";
}
@RequestMapping("/tologin")
public String tologin(){
return "login";
}
}
anon:无需认证就可以访问
authc:必须认证了才能访问
user:必须拥有记住我 功能才能访问
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
//3
//shiroFileterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anon:无需认证就可以访问
authc:必须认证了才能访问
user:必须拥有记住我 功能才能访问
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
//设置拦截
Map<String, String> filemap = new LinkedHashMap<>();
//授权,正常的情况下,没有授权会跳转到未授权的页面
filemap.put("/user/*","authc");
//设置没有权限登录跳转tologin
bean.setLoginUrl("/tologin");
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
spring:
messages:
basename: i18n.login
datasource:
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: root123
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#Spring Boot 默认是不注入这些属性值的,需要自己绑定
#druid 数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
# filters: stat,wall,log4j
filters: stat,wall
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
mybatis:
type-aliases-package: com.xiaozhi.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`pwd` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`perms` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 110 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, ‘小智‘, ‘123456‘, ‘user:update‘);
INSERT INTO `user` VALUES (2, ‘admin‘, ‘123456‘, ‘user:add‘);
INSERT INTO `user` VALUES (3, ‘root‘, ‘123456‘, NULL);
INSERT INTO `user` VALUES (4, ‘小欧‘, ‘123645‘, NULL);
INSERT INTO `user` VALUES (5, ‘张三‘, ‘123546‘, NULL);
INSERT INTO `user` VALUES (6, ‘张姐‘, ‘123456‘, NULL);
INSERT INTO `user` VALUES (7, ‘张小名‘, ‘1234562‘, NULL);
INSERT INTO `user` VALUES (8, ‘ouxinxin‘, ‘22222‘, NULL);
INSERT INTO `user` VALUES (9, ‘xiaoxss‘, ‘3333‘, NULL);
SET FOREIGN_KEY_CHECKS = 1;

package com.xiaozhi.pojo;
/**
* @Author Administrator
* @Date 2021/6/20 8:23
* @Version 1.0
*/
public class User {
private int id;
private String name;
private String pwd;
private String perms;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name=‘" + name + ‘\‘‘ +
", pwd=‘" + pwd + ‘\‘‘ +
‘}‘;
}
public String getPerms() {
return perms;
}
public void setPerms(String perms) {
this.perms = perms;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
package com.xiaozhi.mapper;
import com.xiaozhi.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/**
* @Author Administrator
* @Date 2021/6/10 20:33
* @Version 1.0
*/
//表示这是一个mybatis的mapper类
@Mapper
@Repository
public interface UserMapper {
//用户登录
// List<Employee> login(@Param("name") String name,@Param("password") String password);
User login(@Param("name") String name);
}
package com.xiaozhi.service;
import com.xiaozhi.pojo.User;
import org.apache.ibatis.annotations.Param;
/**
* @Author Administrator
* @Date 2021/6/20 8:26
* @Version 1.0
*/
public interface UserService {
User login(String name);
}
package com.xiaozhi.service;
import com.xiaozhi.mapper.UserMapper;
import com.xiaozhi.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Author Administrator
* @Date 2021/6/20 8:26
* @Version 1.0
*/
@Service("UserService")
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User login(String name) {
return userMapper.login(name);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaozhi.mapper.UserMapper">
<select id="login" resultType="User">
select * from mybatis.user where name=#{name}
</select>
</mapper>
@RequestMapping("/login")
public String login(String username,String password,Model model){
// 获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
// 执行登录方法
subject.login(token);
return "index";
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){
//密码错误
model.addAttribute("msg","密码错误");
return "login";
}
}
@Autowired
private UserMapper userMapper;
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了=》授权doGetAuthenticationInfo");
UsernamePasswordToken usernameToken = (UsernamePasswordToken) authenticationToken;
User user = userMapper.login(usernameToken.getUsername());
if (user==null){
return null;
}
Subject currentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
session.setAttribute("loginUser",user);
//密码认证,shiro做
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}UsernamePasswordToken usernameToken = (UsernamePasswordToken) authenticationToken;
User user = userMapper.login(usernameToken.getUsername());
if (user==null){
return null;
}
Subject currentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
session.setAttribute("loginUser",user);
//密码认证,shiro做
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
//3
//shiroFileterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anon:无需认证就可以访问
authc:必须认证了才能访问
user:必须拥有记住我 功能才能访问
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
//设置拦截
Map<String, String> filemap = new LinkedHashMap<>();
//授权,正常的情况下,没有授权会跳转到未授权的页面
filemap.put("/user/add","perms[user:add]");
filemap.put("/user/update","perms[user:update]");
filemap.put("/user/*","authc");
//设置没有权限登录跳转
bean.setLoginUrl("/tologin");
//未授权跳转页面
bean.setUnauthorizedUrl("/noauth");
bean.setFilterChainDefinitionMap(filemap);
return bean;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=》授权doGetAuthorizationInfo");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//拿到当前登录的这个对象
Subject subject = SecurityUtils.getSubject();
//拿到user对象
User currentUser = (User) subject.getPrincipal();
simpleAuthorizationInfo.addStringPermission(currentUser.getPerms());
return simpleAuthorizationInfo;
}System.out.println("执行了=》授权doGetAuthorizationInfo");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//拿到当前登录的这个对象
Subject subject = SecurityUtils.getSubject();
//拿到user对象
User currentUser = (User) subject.getPrincipal();
simpleAuthorizationInfo.addStringPermission(currentUser.getPerms());
return simpleAuthorizationInfo;
<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
<!--从session中判断值-->
<div th:if="${session.loginUser==null}">
<a th:href="@{/tologin}">登录</a>
</div>
<div th:if="${session.loginUser!=null}">
<a th:href="@{/loginout}">注销</a>
</div>
<p th:text="${msg}"></p>
<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}" >add</a>
</div>
<div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">update</a>
</div>
</body>
</html>
![]() |
|

create table users(
id int primary key auto_increment,
username varchar(60) not null unique,
password varchar(20) not null,
password_salt varchar(20)
);
insert into users(username,password) values(‘zhangsan‘,‘123456‘);
insert into users(username,password) values(‘lisi‘,‘123456‘);
insert into users(username,password) values(‘wangwu‘,‘123456‘);
insert into users(username,password) values(‘zhaoliu‘,‘123456‘);
insert into users(username,password) values(‘chenqi‘,‘123456‘);
create table user_roles(
id int primary key auto_increment,
username varchar(60) not null,
role_name varchar(100) not null
);
-- admin系统管理员
-- cmanager 库管人员
-- xmanager 销售人员
-- kmanager 客服人员
-- zmanager 行政人员
insert into user_roles(username,role_name) values(‘zhangsan‘,‘admin‘);
insert into user_roles(username,role_name) values(‘lisi‘,‘cmanager‘);
insert into user_roles(username,role_name) values(‘wangwu‘,‘xmanager‘);
insert into user_roles(username,role_name) values(‘zhaoliu‘,‘kmanager‘);
insert into user_roles(username,role_name) values(‘chenqi‘,‘zmanager‘);
create table roles_permissions(
id int primary key auto_increment,
role_name varchar(100) not null,
permission varchar(100) not null
);
-- 权限 sys:c:save sys:c:delete...
-- 管理员具备所有权限
insert into roles_permissions(role_name,permission) values("admin","*");
-- 库管人员
insert into roles_permissions(role_name,permission) values("cmanager","sys:c:save");
insert into roles_permissions(role_name,permission) values("cmanager","sys:c:delete");
insert into roles_permissions(role_name,permission) values("cmanager","sys:c:update");
insert into roles_permissions(role_name,permission) values("cmanager","sys:c:find");
-- 销售人员
insert into roles_permissions(role_name,permission) values("xmanager","sys:c:find");
insert into roles_permissions(role_name,permission) values("xmanager","sys:x:save");
insert into roles_permissions(role_name,permission) values("xmanager","sys:x:delete");
insert into roles_permissions(role_name,permission) values("xmanager","sys:x:update");
insert into roles_permissions(role_name,permission) values("xmanager","sys:x:find");
insert into roles_permissions(role_name,permission) values("xmanager","sys:k:save");
insert into roles_permissions(role_name,permission) values("xmanager","sys:k:delete");
insert into roles_permissions(role_name,permission) values("xmanager","sys:k:update");
insert into roles_permissions(role_name,permission) values("xmanager","sys:k:find");
-- 客服人员
insert into roles_permissions(role_name,permission) values("kmanager","sys:k:find");
insert into roles_permissions(role_name,permission) values("kmanager","sys:k:update");
-- 新增人员
insert into roles_permissions(role_name,permission) values("zmanager","sys:*:find");
创建SpringBoot应用
整合Druid和MyBatis
整合shiro
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
@Configuration
public class ShiroConfig {
/***
*
* JdbcRealm
* **/
@Bean
public JdbcRealm getJdbcRealm(DataSource dataSource){
JdbcRealm jdbcRealm = new JdbcRealm();
//JdbcRealm会自行从数据库查询用户及权限数据(数据库的表结构要符合JdbcRealm的规范)
jdbcRealm.setDataSource(dataSource);
//JdbcRealm默认开启认证功能,需要手动开启授权功能
jdbcRealm.setPermissionsLookupEnabled(true);
return jdbcRealm;
}
/***
*
* JdbcRealm
* **/
@Bean
public DefaultWebSecurityManager getdefaultWebSecurityManager(JdbcRealm jdbcRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//securityManager要完成校验,需要realm
securityManager.setRealm(jdbcRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactory(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
//过滤器就是shiro就行权限校验的核心,进行认证和授权是需要securityManager
filter.setSecurityManager(securityManager);
//设置shiro的拦截规则
// anon:无需认证即可访问,游客身份。
// authc:必须认证(登录)才能访问。
// authcBasic:需要通过 httpBasic 认证。
// user:rememberMe的用户访问
// perms:对应的权限可访问
// role:对应的角色可访问
HashMap<String, String> filterMap = new HashMap<>();
filterMap.put("/","anon");
filterMap.put("/login.html","anon");
filterMap.put("/index.html","anon");
filterMap.put("/welcome.html","anon");
filterMap.put("/regist.html","anon");
filterMap.put("/user/login","anon");
filterMap.put("/user/regist","anon");
filterMap.put("/static/**","anon");
filterMap.put("/x-admin/**","anon");
filterMap.put("/**","authc");
filter.setFilterChainDefinitionMap(filterMap);
//设置登录页
filter.setLoginUrl("/");
//设置没有权限页面
filter.setUnauthorizedUrl("/login.html");
return filter;
}
}
当用户认证进入到主页面之后,需要显示用户信息及当前用户的权限信息;Shiro就提供了一套标签用于在页面来进行权限数据的呈现
Shiro提供了可供JSP使用的标签以及Thymeleaf中标签
JSP页面中引用:
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
Thymeleaf模版中引用:
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
@Configuration
public class ShiroConfig {
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
//...
}
<html xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
...
</html>
guest,判断用户是否是游客身份,如果是游客身份则显示此标签内容
<shiro:guest>
欢迎游客访问,<a href="login.html">登录</a>
</shiro:guest>
user,判断用户是否是认证身份,如果是认证身份则显示此标签内容
principal,获取当前登录用户名
<shiro:user>
用户[<shiro:principal/>]欢迎您!
</shiro:user>
notAuthenticated/authenticated
hasRole
hasPermission
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
index
<hr/>
<shiro:guest>
欢迎游客访问,<a href="login.html">登录</a>
</shiro:guest>
<shiro:user>
用户[<shiro:principal/>]欢迎您!
当前用户为<shiro:hasRole name="admin">超级管理员</shiro:hasRole>
<shiro:hasRole name="cmanager">仓管人员</shiro:hasRole>
<shiro:hasRole name="xmanager">销售人员</shiro:hasRole>
<shiro:hasRole name="kmanager">客服人员</shiro:hasRole>
<shiro:hasRole name="zmanager">行政人员</shiro:hasRole>
</shiro:user>
<hr/>
仓库管理
<ul>
<shiro:hasPermission name="sys:c:save"><li><a href="#">入库</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:c:delete"><li><a href="#">出库</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:c:update"><li><a href="#">修改</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:c:find"><li><a href="#">查询</a></li></shiro:hasPermission>
</ul>
订单管理
<ul>
<shiro:hasPermission name="sys:x:save"><li><a href="#">添加订单</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:x:delete"><li><a href="#">删除订单</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:x:update"><li><a href="#">修改订单</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:x:find"><li><a href="#">查询订单</a></li></shiro:hasPermission>
</ul>
客户管理
<ul>
<shiro:hasPermission name="sys:k:save"><li><a href="#">添加客户</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:k:delete"><li><a href="#">删除客户</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:k:update"><li><a href="#">修改客户</a></li></shiro:hasPermission>
<shiro:hasPermission name="sys:k:find"><li><a href="#">查询客户</a></li></shiro:hasPermission>
</ul>
</body>
</html>
使用JdbcRealm可以完成用户权限管理,但是我们必须提供JdbcRealm规定的数据表结构;如果在我们的项目开发中 ,这个JdbcRealm规定的数据表结构不能满足开发需求,该如何处理呢?
| 
-- 用户信息表
create table tb_users(
user_id int primary key auto_increment,
username varchar(60) not null unique,
password varchar(20) not null,
password_salt varchar(60)
);
insert into tb_users(username,password) values(‘zhangsan‘,‘123456‘);
insert into tb_users(username,password) values(‘lisi‘,‘123456‘);
insert into tb_users(username,password) values(‘wangwu‘,‘123456‘);
insert into tb_users(username,password) values(‘zhaoliu‘,‘123456‘);
insert into tb_users(username,password) values(‘chenqi‘,‘123456‘);
-- 角色信息表
create table tb_roles(
role_id int primary key auto_increment,
role_name varchar(60) not null
);
insert into tb_roles(role_name) values(‘admin‘);
insert into tb_roles(role_name) values(‘cmanager‘); -- 仓管
insert into tb_roles(role_name) values(‘xmanager‘); -- 销售
insert into tb_roles(role_name) values(‘kmanager‘); -- 客服
insert into tb_roles(role_name) values(‘zmanager‘); -- 行政
-- 权限信息表
create table tb_permissions(
permission_id int primary key auto_increment, -- 1
permission_code varchar(60) not null, -- sys:c:find
permission_name varchar(60) -- 仓库查询
);
insert into tb_permissions(permission_code,permission_name) values(‘sys:c:save‘,‘入库‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:c:delete‘,‘出库‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:c:update‘,‘修改‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:c:find‘,‘查询‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:x:save‘,‘新增订单‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:x:delete‘,‘删除订单‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:x:update‘,‘修改订单‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:x:find‘,‘查询订单‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:k:save‘,‘新增客户‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:k:delete‘,‘删除客户‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:k:update‘,‘修改客户‘);
insert into tb_permissions(permission_code,permission_name) values(‘sys:k:find‘,‘查询客户‘);
-- 用户角色表
create table tb_urs(
uid int not null,
rid int not null
-- primary key(uid,rid),
-- constraint FK_user foreign key(uid) references tb_users(user_id),
-- constraint FK_role foreign key(rid) references tb_roles(role_id)
);
insert into tb_urs(uid,rid) values(1,1);
insert into tb_urs(uid,rid) values(1,2);
insert into tb_urs(uid,rid) values(1,3);
insert into tb_urs(uid,rid) values(1,4);
insert into tb_urs(uid,rid) values(1,5);
insert into tb_urs(uid,rid) values(2,2);
insert into tb_urs(uid,rid) values(3,3);
insert into tb_urs(uid,rid) values(4,4);
insert into tb_urs(uid,rid) values(5,5);
-- 角色权限表
create table tb_rps(
rid int not null,
pid int not null
);
-- 给仓管角色分配权限
insert into tb_rps(rid,pid) values(2,1);
insert into tb_rps(rid,pid) values(2,2);
insert into tb_rps(rid,pid) values(2,3);
insert into tb_rps(rid,pid) values(2,4);
-- 给销售角色分配权限
insert into tb_rps(rid,pid) values(3,4);
insert into tb_rps(rid,pid) values(3,5);
insert into tb_rps(rid,pid) values(3,6);
insert into tb_rps(rid,pid) values(3,7);
insert into tb_rps(rid,pid) values(3,8);
insert into tb_rps(rid,pid) values(3,9);
insert into tb_rps(rid,pid) values(3,10);
insert into tb_rps(rid,pid) values(3,11);
insert into tb_rps(rid,pid) values(3,12);
-- 给客服角色分配权限
insert into tb_rps(rid,pid) values(4,11);
insert into tb_rps(rid,pid) values(4,12);
-- 给行政角色分配权限
insert into tb_rps(rid,pid) values(5,4);
insert into tb_rps(rid,pid) values(5,8);
insert into tb_rps(rid,pid) values(5,12);
Shiro进行认证需要用户信息:
Shiro进行授权管理需要当前用户的角色和权限
@Data
public class User {
private Integer userId;
private String userName;
private String userPwd;
private String pwdSalt;
}
public interface UserDAO {
public User queryUserByUsername(String username);
}
映射配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaozhi.dao.UserDao">
<select id="queryUserByUsername" resultType="user">
select * from shiro1.tb_users
where username=#{username}
</select>
</mapper>
创建DAO
public interface RoleDAO {
public Set<String> queryRoleNamesByUsername(String username);
}
映射配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaozhi.dao.RoleDao">
<select id="queryRoleNamesByUsername" resultSets="java.util.Set" resultType="string">
select role_name
from shiro1.tb_users inner join shiro1.tb_urs
on tb_users.user_id = tb_urs.uid
inner join shiro1.tb_roles
on tb_urs.rid = tb_roles.role_id
where tb_users.username=#{username}
</select>
</mapper>
创建DAO
public interface PermissionDAO {
public Set<String> queryPermissionsByUsername(String username);
}
映射配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaozhi.dao.PermissionDao">
<select id="queryPermissionsByUsername" resultSets="java.util.Set" resultType="string">
select tb_permissions.permission_code from shiro1.tb_users
inner join shiro1.tb_urs on tb_users.user_id=tb_urs.uid
inner join shiro1.tb_roles on tb_urs.rid=tb_roles.role_id
inner join shiro1.tb_rps on tb_roles.role_id=tb_rps.rid
inner join shiro1.tb_permissions on tb_rps.pid=tb_permissions.permission_id
where tb_users.username=#{username}
</select>
</mapper>
导入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
配置Shiro-基于Java配置方式
package com.xiaozhi.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.xiaozhi.realm.MyRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* @Author Administrator
* @Date 2021/8/15 23:06
* @Version 1.0
*/
@Configuration
public class ShiroConfig {
//配置spring-shrio-thymeleaf的使用
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
//自定义Realm
@Bean
public MyRealm getMyRealm(){
return new MyRealm();
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
//过滤器就是shiro就行权限校验的核心,进行认证和授权是需要SecurityManager的
filter.setSecurityManager(securityManager);
Map<String,String> filterMap = new HashMap<>();
filterMap.put("/","anon");
filterMap.put("/index.html","anon");
filterMap.put("/login.html","anon");
filterMap.put("/regist.html","anon");
filterMap.put("/user/login","anon");
filterMap.put("/user/regist","anon");
filterMap.put("/layui/**","anon");
filterMap.put("/**","authc");
filter.setFilterChainDefinitionMap(filterMap);
filter.setLoginUrl("/login.html");
//设置未授权访问的页面路径()
filter.setUnauthorizedUrl("/login.html");
return filter;
}
}
自定义Realm
/**
* 1.创建一个类继承AuthorizingRealm类(实现了Realm接口的类)
* 2.重写doGetAuthorizationInfo和doGetAuthenticationInfo方法
* 3.重写getName方法返回当前realm的一个自定义名称
*/
public class MyRealm extends AuthorizingRealm {
@Resource
private UserDAO userDAO;
@Resource
private RoleDAO roleDAO;
@Resource
private PermissionDAO permissionDAO;
public String getName() {
return "myRealm";
}
/**
* 获取授权数据(将当前用户的角色及权限信息查询出来)
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户的用户名
String username = (String) principalCollection.iterator().next();
//根据用户名查询当前用户的角色列表
Set<String> roleNames = roleDAO.queryRoleNamesByUsername(username);
//根据用户名查询当前用户的权限列表
Set<String> ps = permissionDAO.queryPermissionsByUsername(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roleNames);
info.setStringPermissions(ps);
return info;
}
/**
* 获取认证的安全数据(从数据库查询的用户的正确数据)
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//参数authenticationToken就是传递的 subject.login(token)
// 从token中获取用户名
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//根据用户名,从数据库查询当前用户的安全数据
User user = userDAO.queryUserByUsername(username);
AuthenticationInfo info = new SimpleAuthenticationInfo(
username, //当前用户用户名
user.getUserPwd(), //从数据库查询出来的安全密码
getName());
return info;
}
}
明文-----(加密规则)-----密文
加密规则可以自定义,在项目开发中我们通常使用BASE64和MD5编码方式
如果数据库用户的密码存储的密文,Shiro该如何完成验证呢?
使用Shiro提供的加密功能,对输入的密码进行加密之后再进行认证。
配置matcher
@Configuration
public class ShiroConfig {
//...
@Bean
public HashedCredentialsMatcher getHashedCredentialsMatcher(){
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//matcher就是用来指定加密规则
//加密方式
matcher.setHashAlgorithmName("md5");
//hash次数
matcher.setHashIterations(1); //此处的循环次数要与用户注册是密码加密次数一致
return matcher;
}
//自定义Realm
@Bean
public MyRealm getMyRealm( HashedCredentialsMatcher matcher ){
MyRealm myRealm = new MyRealm();
myRealm.setCredentialsMatcher(matcher);
return myRealm;
}
//...
}
registh.html
<form action="/user/regist" method="post">
<p>帐号:<input type="text" name="userName"/></p>
<p>密码:<input type="text" name="userPwd"/></p>
<p><input type="submit" value="提交注册"/></p>
</form>
UserController
@Controller
@RequestMapping("user")
public class UserController {
@Resource
private UserServiceImpl userService;
@RequestMapping("/regist")
public String regist(String userName,String userPwd) {
System.out.println("------注册");
//注册的时候要对密码进行加密存储
Md5Hash md5Hash = new Md5Hash(userPwd);
System.out.println("--->>>"+ md5Hash.toHex());
//加盐加密
int num = new Random().nextInt(90000)+10000; //10000—99999
String salt = num+"";
Md5Hash md5Hash2 = new Md5Hash(userPwd,salt);
System.out.println("--->>>"+md5Hash2);
//加盐加密+多次hash
Md5Hash md5Hash3 = new Md5Hash(userPwd,salt,3);
System.out.println("--->>>"+md5Hash3);
//SimpleHash hash = new SimpleHash("md5",userPwd,num,3);
//将用户信息保存到数据库时,保存加密后的密码,如果生成的随机盐,盐也要保存
return "login";
}
}
自定义Realm
public class MyRealm extends AuthorizingRealm {
@Resource
private UserDAO userDAO;
@Resource
private RoleDAO roleDAO;
@Resource
private PermissionDAO permissionDAO;
public String getName() {
return "myRealm";
}
/**
* 获取认证的安全数据(从数据库查询的用户的正确数据)
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//参数authenticationToken就是传递的 subject.login(token)
// 从token中获取用户名
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//根据用户名,从数据库查询当前用户的安全数据
User user = userDAO.queryUserByUsername(username);
// AuthenticationInfo info = new SimpleAuthenticationInfo(
// username, //当前用户用户名
// user.getUserPwd(), //从数据库查询出来的安全密码
// getName());
//如果数据库中用户的密码是加了盐的
AuthenticationInfo info = new SimpleAuthenticationInfo(
username, //当前用户用户名
user.getUserPwd(), //从数据库查询出来的安全密码
ByteSource.Util.bytes(user.getPwdSalt()),
getName());
return info;
}
}
//定义退出页面
filterMap.put("/loginout","logout");
<a href="loginout">退出</a>
用户登录成功之后,要进行响应的操作就需要有对应的权限;在进行操作之前对权限进行检查—授权
权限控制通常有两类做法:
<shiro:hasPermission name="sys:c:save">
<dd><a href="javascript:;">入库</a></dd>
</shiro:hasPermission>
在shiro过滤器中对请求的url进行权限设置
filterMap.put("/c_add.html","perms[sys:c:save]");
//设置未授权访问的页面路径—当权限不足时显示此页面
filter.setUnauthorizedUrl("/lesspermission.html");
配置Spring对Shiro注解的支持:ShiroConfig.java
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setProxyTargetClass(true);
return autoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor( DefaultWebSecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
在请求的控制器添加权限注解
@Controller
@RequestMapping("customer")
public class CustomerController {
@RequestMapping("/list")
@ResponseBody
//如果没有 sys:k:find 权限,则不允许执行此方法
@RequiresPermissions("sys:k:find")
// @RequiresRoles("")
public String list(){
System.out.println("----------->查询客户信息");
return "ok";
}
}
通过全局异常处理,指定权限不足时的页面跳转
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler
public String doException(Exception e){
if(e instanceof AuthorizationException){
return "lesspermission";
}
return null;
}
}
Subject subject = SecurityUtils.getSubject();
if(subject.isPermitted("sys:k:find")){
System.out.println("----------->查询客户信息");
return "customer_list";
}else{
return "lesspermission";
}
| 使用Shiro进行权限管理过程中,每次授权都会访问realm中的doGetAuthorizationInfo方法查询当前用户的角色及权限信息,如果系统的用户量比较大则会对数据库造成比较大的压力 |
|---|
| Shiro支持缓存以降低对数据库的访问压力(缓存的是授权信息) |
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
在resources目录下创建一个xml文件(ehcache.xml)
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" dynamicConfig="false">
<!--diskStore:缓存数据持久化的目录 地址 -->
<diskStore path="C:\TEMP" />
<cache name="users" timeToLiveSeconds="300" maxEntriesLocalHeap="1000"/>
<defaultCache name="defaultCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
<!--缓存淘汰策略:当缓存空间比较紧张时,我们要存储新的数据进来,就必然要删除一些老的数据
LRU 最近最少使用
FIFO 先进先出
LFU 最少使用
-->
</ehcache>
配置说明
maxElementsInMemory 内存中最大缓存对象数,看着自己的heap大小来设置
eternal:true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false
overflowToDisk:true表示当内存缓存的对象数目达到了maxElementsInMemory界限后,
会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。
maxElementsOnDisk:硬盘中最大缓存对象数,若是0表示无穷大。
diskSpoolBufferSizeMB:磁盘缓存区大小,默认为30MB。每个Cache都应该有自己的一个缓存区。
diskPersistent:是否缓存虚拟机重启期数据。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认为120秒。
timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0, 则表示对象可以无限期地处于空闲状态。
timeToLiveSeconds:设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后, 如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期, EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
ShiroConfig.java
@Bean
public EhCacheManager getEhCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return ehCacheManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
return securityManager;
}
Shiro进行认证和授权是基于session实现的,Shiro包含了对session的管理
如果我们需要对session进行管理
配置自定义SessionManager:ShiroConfig.java
@Bean
public DefaultWebSessionManager getDefaultWebSessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
System.out.println("----------"+sessionManager.getGlobalSessionTimeout()); // 1800000
//配置sessionManager
sessionManager.setGlobalSessionTimeout(5*60*1000);
return sessionManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
securityManager.setSessionManager(getDefaultWebSessionManager());
return securityManager;
}
// anon 表示未认证可访问的url
// user 表示记住我可访问的url(已认证也可以访问)
//authc 表示已认证可访问的url
//perms 表示必须具备指定的权限才可访问
//logout 表示指定退出的url
filterMap.put("/","anon");
filterMap.put("/index.html","user");
filterMap.put("/login.html","anon");
filterMap.put("/regist.html","anon");
filterMap.put("/user/login","anon");
filterMap.put("/user/regist","anon");
filterMap.put("/layui/**","anon");
filterMap.put("/**","authc");
filterMap.put("/c_add.html","perms[sys:c:save]");
filterMap.put("/exit","logout");
@Bean
public CookieRememberMeManager cookieRememberMeManager(){
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
//cookie必须设置name
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setMaxAge(30*24*60*60);
rememberMeManager.setCookie(cookie);
return rememberMeManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
securityManager.setSessionManager(getDefaultWebSessionManager());
//设置remember管理器
securityManager.setRememberMeManager(cookieRememberMeManager());
return securityManager;
}
<form action="/user/login" method="post">
<p>帐号:<input type="text" name="userName"/></p>
<p>密码:<input type="text" name="userPwd"/></p>
<p>记住我:<input type="checkbox" name="rememberMe"/></p>
<p><input type="submit" value="登录"/></p>
</form>
@Controller
@RequestMapping("user")
public class UserController {
@Resource
private UserServiceImpl userService;
@RequestMapping("login")
public String login(String userName,String userPwd,boolean rememberMe){
try {
userService.checkLogin(userName,userPwd,rememberMe);
System.out.println("------登录成功!");
return "index";
} catch (Exception e) {
System.out.println("------登录失败!");
return "login";
}
}
//...
}
@Service
public class UserServiceImpl {
public void checkLogin(String userName, String userPwd,boolean rememberMe) throws Exception {
//Shiro进行认证 ——入口
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd);
token.setRememberMe(rememberMe);
subject.login(token);
}
}
定义多个Realm
UserRealm
public class UserRealm extends AuthorizingRealm {
Logger logger = LoggerFactory.getLogger(UserRealm.class);
@Override
public String getName() {
return "UserRealm";
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("--------------------------------UserRealm");
//从token中获取username
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//根据username从users表中查询用户信息
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,"123456",getName());
return info;
}
}
ManagerRealm
public class ManagerRealm extends AuthorizingRealm {
Logger logger = LoggerFactory.getLogger(ManagerRealm.class);
@Override
public String getName() {
return "ManagerRealm";
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("--------------------------------ManagerRealm");
//从token中获取username
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//根据username从吗managers表中查询用户信息
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,"222222",getName());
return info;
}
}
在ShiroConfig.java中为SecurityManager配置多个Realm
@Configuration
public class ShiroConfig {
@Bean
public UserRealm userRealm(){
UserRealm userRealm = new UserRealm();
return userRealm;
}
@Bean
public ManagerRealm managerRealm(){
ManagerRealm managerRealm = new ManagerRealm();
return managerRealm;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//securityManager中配置多个realm
Collection<Realm> realms = new ArrayList<>();
realms.add(userRealm());
realms.add(managerRealm());
securityManager.setRealms(realms);
return securityManager;
}
//...
}
测试代码:
login.html
<form action="user/login" method="post">
<p>帐号:<input type="text" name="userName"/></p>
<p>密码:<input type="text" name="userPwd"/></p>
<p><input type="radio" name="loginType" value="User"/>普通用户
<input type="radio" name="loginType" value="Manager"/>管理员</p>
<p><input type="submit" value="登录"/></p>
</form>
UserController.java
@Controller
@RequestMapping("user")
public class UserController {
Logger logger = LoggerFactory.getLogger(UserController.class);
@RequestMapping("login")
public String login(String userName,String userPwd, String loginType){
logger.info("~~~~~~~~~~~~~UserController-login");
try{
UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd);
Subject subject = SecurityUtils.getSubject();
subject.login(token);
return "index";
}catch (Exception e){
return "login";
}
}
}
![]() |
|
shiro自带的org.apache.shiro.authc.pam.ModularRealmAuthenticator,其中决定使用的Realm的是doAuthenticate()方法,源代码如下
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
this.assertRealmsConfigured();
Collection<Realm> realms = this.getRealms();
// this.doMultiRealmAuthentication(realms, authenticationToken);中的realms参数就是认证会执行的Realm
return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);
}
实现案例:用户不同身份登录执行不同的Realm
自定义Realm(UserRealm\ManagerRealm)
Realm的声明及配置
自定义Token
public class MyToken extends UsernamePasswordToken {
private String loginType;
public MyToken(String userName,String userPwd, String loginType) {
super(userName,userPwd);
this.loginType = loginType;
}
public String getLoginType() {
return loginType;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
}
自定义认证器
public class MyModularRealmAuthenticator extends ModularRealmAuthenticator {
Logger logger = LoggerFactory.getLogger(MyModularRealmAuthenticator.class);
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("------------------------------MyModularRealmAuthenticator");
this.assertRealmsConfigured();
Collection<Realm> realms = this.getRealms();
MyToken token = (MyToken) authenticationToken;
String loginType = token.getLoginType(); // User
logger.info("------------------------------loginType:"+loginType);
Collection<Realm> typeRealms = new ArrayList<>();
for(Realm realm:realms){
if(realm.getName().startsWith(loginType)){ //UserRealm
typeRealms.add(realm);
}
}
if(typeRealms.size()==1){
return this.doSingleRealmAuthentication((Realm)typeRealms.iterator().next(), authenticationToken);
}else{
return this.doMultiRealmAuthentication(typeRealms, authenticationToken);
}
}
}
配置自定义认证器
@Configuration
public class ShiroConfig {
@Bean
public UserRealm userRealm(){
UserRealm userRealm = new UserRealm();
return userRealm;
}
@Bean
public ManagerRealm managerRealm(){
ManagerRealm managerRealm = new ManagerRealm();
return managerRealm;
}
@Bean
public MyModularRealmAuthenticator myModularRealmAuthenticator(){
MyModularRealmAuthenticator myModularRealmAuthenticator = new MyModularRealmAuthenticator();
return myModularRealmAuthenticator;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//配置自定义认证器(放在realms设置之前)
securityManager.setAuthenticator(myModularRealmAuthenticator());
//securityManager中配置多个realm
Collection<Realm> realms = new ArrayList<>();
realms.add(userRealm());
realms.add(managerRealm());
securityManager.setRealms(realms);
return securityManager;
}
//...
}
测试: 控制器接受数据进行认证
<form action="user/login" method="post">
<p>帐号:<input type="text" name="userName"/></p>
<p>密码:<input type="text" name="userPwd"/></p>
<p><input type="radio" name="loginType" value="User" checked/>普通用户
<input type="radio" name="loginType" value="Manager"/>管理员</p>
<p><input type="submit" value="登录"/></p>
</form>
UserController.java
@Controller
@RequestMapping("user")
public class UserController {
Logger logger = LoggerFactory.getLogger(UserController.class);
@RequestMapping("login")
public String login(String userName,String userPwd, String loginType){
logger.info("~~~~~~~~~~~~~UserController-login");
try{
//UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd);
MyToken token = new MyToken(userName,userPwd,loginType);
Subject subject = SecurityUtils.getSubject();
subject.login(token);
return "index";
}catch (Exception e){
return "login";
}
}
}
原文:https://www.cnblogs.com/xiaozhizxj/p/15202243.html