目录
一、搭建项目
1、创建SpringBoot项目
2、创建配置类
自定义UserRealm
ShiroConfig
3、index和login页面编写
4、controller层编写
5、在UserRealm中实现认证
在ShiroConfig编写资源访问限制
二、MD5、Salt的注册
1、新建register.html
2、新建表t_user
3、application.yml
4、新建实体类
5、新建UserMapper
6、新建service层和SaltUtil
(1)UserService
(2)UserServiceImpl
(3)SaltUtil
(4)ShiroConstant
7、编写Controller
8、编写ShiroConfig
三、MD5、Salt的认证
1、编写Service层
2、编写UserRealm
3、编写ApplicationContextUtil
4、编写ShiroConfig
四、Shiro基于角色授权
1、创建表
2、编写User和Role的实体类
3、编写Mapper层
4、编写Service层
5、Realm中实现授权
6、编写Index页面
五、Shiro基于权限的授权
1、新建表新增t_perm和t_role_permn表
2、编写Role和Perms实体类
3、编写Mapper层
4、编写Service层
5、编写userRealm
6、编写Index页面
六、EhCache实现缓存
Shiro的简介和基本使用这里就不介绍了
快速入门请跳转到:Shiro快速入门
一、搭建项目
1、创建SpringBoot项目
- 新建SpringBoot项目时,勾选web、thymeleaf、lombok
- 新建SpringBoot项目时,勾选web、thymeleaf、lombok
导入相关依赖
org.apache.shiro
shiro-spring
1.4.1
2、创建配置类
自定义UserRealm
public class UerRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证");
return null;
}
}
ShiroConfig
public class UerRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证");
return null;
}
}
ShiroConfig
这个类是Shiro的核心配置类,里面继承了ShiroFilter、SecurityManager和上面的自定义的Realm
@Configuration
public class ShiroConfig {
//1.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
//关联CustomerRealm
securityManager.setRealm(uerRealm);
return securityManager;
}
//创建realm对象
@Bean
public UserRealm getRealm(){
return new UserRealm();
}
}
Shiro中常见过滤器
| 配置缩写 | 对应的过滤器 | 功能 |
|---|---|---|
| anon | AnonymousFilter | 指定url可以匿名访问 |
| authc | FormAuthenticationFilter | 指定url需要form表单登录,默认会从请求中获取username、password,rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。 |
| authcBasic | BasicHttpAuthenticationFilter | 指定url需要basic登录 |
| logout | LogoutFilter | 登出过滤器,配置指定url就可以实现退出功能,非常方便 |
| noSessionCreation | NoSessionCreationFilter | 禁止创建会话 |
| perms | PermissionsAuthorizationFilter | 需要指定权限才能访问 |
| port | PortFilter | 需要指定端口才能访问 |
| rest | HttpMethodPermissionFilter | 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释 |
| roles | RolesAuthorizationFilter | 需要指定角色才能访问 |
| ssl | SslFilter | 需要https请求才能访问 |
| user | UserFilter | 需要已登录或“记住我”的用户才能访问 |
3、index和login页面编写
Title
系统主页
- 用户管理
- 订单管理
Title
用户登录
4、controller层编写
@Controller
public class MyController {
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/toIndex")
public String toLogin(){
return "index";
}
@RequestMapping("/login")
public String login(String username,String password){
// 获取当前登录用户
Subject subject = SecurityUtils.getSubject();
try {
// 执行登录操作
subject.login(new UsernamePasswordToken(username,password));
// 认证通过后直接跳转到index.html
return "redirect:/toIndex";
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误~");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("密码错误~");
} catch (Exception e) {
e.printStackTrace();
}
// 如果认证失败仍然回到登录页面
return "redirect:/toLogin";
}
}
5、在UserRealm中实现认证
public class UserRealm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取当前登录的主题
String principal = (String) token.getPrincipal();
// 模拟数据库返回的数据
if("admin".equals(principal)){
return new SimpleAuthenticationInfo(principal,"123456",this.getName());
}
return null;
}
}
public class UserRealm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取当前登录的主题
String principal = (String) token.getPrincipal();
// 模拟数据库返回的数据
if("admin".equals(principal)){
return new SimpleAuthenticationInfo(principal,"123456",this.getName());
}
return null;
}
}
上面的认证中只要我们输入的用户名是admin,密码123456就可以认证通过进入到主页
在ShiroConfig编写资源访问限制
@Configuration
public class ShiroConfig {
//1.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map map = new HashMap();
map.put("/toIndex","anon");
map.put("/toLogin","anon"); // anon 设置为公共资源,放行要注意anon和authc的顺序
map.put("/","authc"); //authc 请求这个资源需要认证和授权
map.put("/index","authc"); //authc 请求这个资源需要认证和授权
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}
//创建realm对象
@Bean
public UserRealm userRealm(){...}
}
测试:可以发现在未登录的前提下直接访问/和/index是无法访问的,会跳转到登录界面
二、MD5、Salt的注册
1、新建register.html
Title
用户注册
Title
用户注册
2、新建表t_user
DROp TABLE IF EXISTS `t_user`;
create table `t_user` (
`id` int (11),
`username` varchar (32),
`password` varchar (32),
`salt` varchar (32),
);
com.alibaba
druid
1.1.12
com.baomidou
mybatis-plus-boot-starter
3.4.1
3、application.yml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=UTC
username: root
password: 123456
# 监控统计拦截的filters
filters: stat,wall,log4j,config
# 配置初始化大小/最小/最大
initial-size: 5
min-idle: 5
max-active: 20
# 获取连接等待超时时间
max-wait: 60000
# 间隔多久进行一次检测,检测需要关闭的空闲连接
time-between-eviction-runs-millis: 60000
# 一个连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
validation-query: SELECT 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
pool-prepared-statements: false
max-pool-prepared-statement-per-connection-size: 20
mybatis-plus:
type-aliases-package: com.christy.shiro.entity
configuration:
map-underscore-to-camel-case: true
4、新建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
private String username;
private String password;
private String salt;
}
5、新建UserMapper
@Mapper
public interface UserMapper extends baseMapper {
}
6、新建service层和SaltUtil
(1)UserService
public interface UserService {
void register(User user);
}
(2)UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public void register(User user) {
// 生成随机盐
String salt = SaltUtil.getSalt(ShiroConstant.SALT_LENGTH);
// 保存随机盐
user.setSalt(salt);
// 生成密码
Md5Hash password = new Md5Hash(user.getPassword(), salt, ShiroConstant.HASH_ITERATORS);
// 保存密码
user.setPassword(password.toHex());
userMapper.insert(user);
}
}
(3)SaltUtil
public class SaltUtil {
public static String getSalt(int n){
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
char aChar = chars[new Random().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}
}
(4)ShiroConstant
public class ShiroConstant {
public static final int SALT_LENGTH = 8;
public static final int HASH_ITERATORS = 1024;
public interface HASH_ALGORITHM_NAME {
String MD5 = "MD5";
}
}
7、编写Controller
@Controller
public class MyController {
@Autowired
private UserService userService;
@RequestMapping("/toLogin")
public String toLogin(){...}
@RequestMapping("/toRegister")
public String toRegister(){...}
@RequestMapping("/toIndex")
public String toLogin(){...}
@RequestMapping("/login")
public String login(String username,String password){...}
@RequestMapping("/register")
public String register(User user){
try {
userService.register(user);
return "redirect:/login.jsp";
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/register.jsp";
}
}
8、编写ShiroConfig
@Configuration
public class ShiroConfig {
//1.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map map = new HashMap();
// anon 设置为公共资源,放行要注意anon和authc的顺序
map.put("/toIndex","anon");
map.put("/toLogin","anon");
map.put("/register","anon");
map.put("/toRegister","anon");
map.put("/","authc");
map.put("/index","authc"); //authc 请求这个资源需要认证和授权
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}
//创建realm对象
@Bean
public UserRealm userRealm(){...}
}
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=UTC
username: root
password: 123456
# 监控统计拦截的filters
filters: stat,wall,log4j,config
# 配置初始化大小/最小/最大
initial-size: 5
min-idle: 5
max-active: 20
# 获取连接等待超时时间
max-wait: 60000
# 间隔多久进行一次检测,检测需要关闭的空闲连接
time-between-eviction-runs-millis: 60000
# 一个连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
validation-query: SELECT 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
pool-prepared-statements: false
max-pool-prepared-statement-per-connection-size: 20
mybatis-plus:
type-aliases-package: com.christy.shiro.entity
configuration:
map-underscore-to-camel-case: true
4、新建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
private String username;
private String password;
private String salt;
}
5、新建UserMapper
@Mapper
public interface UserMapper extends baseMapper {
}
6、新建service层和SaltUtil
(1)UserService
public interface UserService {
void register(User user);
}
(2)UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public void register(User user) {
// 生成随机盐
String salt = SaltUtil.getSalt(ShiroConstant.SALT_LENGTH);
// 保存随机盐
user.setSalt(salt);
// 生成密码
Md5Hash password = new Md5Hash(user.getPassword(), salt, ShiroConstant.HASH_ITERATORS);
// 保存密码
user.setPassword(password.toHex());
userMapper.insert(user);
}
}
(3)SaltUtil
public class SaltUtil {
public static String getSalt(int n){
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
char aChar = chars[new Random().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}
}
(4)ShiroConstant
public class ShiroConstant {
public static final int SALT_LENGTH = 8;
public static final int HASH_ITERATORS = 1024;
public interface HASH_ALGORITHM_NAME {
String MD5 = "MD5";
}
}
7、编写Controller
@Controller
public class MyController {
@Autowired
private UserService userService;
@RequestMapping("/toLogin")
public String toLogin(){...}
@RequestMapping("/toRegister")
public String toRegister(){...}
@RequestMapping("/toIndex")
public String toLogin(){...}
@RequestMapping("/login")
public String login(String username,String password){...}
@RequestMapping("/register")
public String register(User user){
try {
userService.register(user);
return "redirect:/login.jsp";
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/register.jsp";
}
}
8、编写ShiroConfig
@Configuration
public class ShiroConfig {
//1.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map map = new HashMap();
// anon 设置为公共资源,放行要注意anon和authc的顺序
map.put("/toIndex","anon");
map.put("/toLogin","anon");
map.put("/register","anon");
map.put("/toRegister","anon");
map.put("/","authc");
map.put("/index","authc"); //authc 请求这个资源需要认证和授权
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}
//创建realm对象
@Bean
public UserRealm userRealm(){...}
}
@Mapper public interface UserMapper extends baseMapper{ }
6、新建service层和SaltUtil
(1)UserService
public interface UserService {
void register(User user);
}
(2)UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public void register(User user) {
// 生成随机盐
String salt = SaltUtil.getSalt(ShiroConstant.SALT_LENGTH);
// 保存随机盐
user.setSalt(salt);
// 生成密码
Md5Hash password = new Md5Hash(user.getPassword(), salt, ShiroConstant.HASH_ITERATORS);
// 保存密码
user.setPassword(password.toHex());
userMapper.insert(user);
}
}
(3)SaltUtil
public class SaltUtil {
public static String getSalt(int n){
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
char aChar = chars[new Random().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}
}
(4)ShiroConstant
public class ShiroConstant {
public static final int SALT_LENGTH = 8;
public static final int HASH_ITERATORS = 1024;
public interface HASH_ALGORITHM_NAME {
String MD5 = "MD5";
}
}
7、编写Controller
@Controller
public class MyController {
@Autowired
private UserService userService;
@RequestMapping("/toLogin")
public String toLogin(){...}
@RequestMapping("/toRegister")
public String toRegister(){...}
@RequestMapping("/toIndex")
public String toLogin(){...}
@RequestMapping("/login")
public String login(String username,String password){...}
@RequestMapping("/register")
public String register(User user){
try {
userService.register(user);
return "redirect:/login.jsp";
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/register.jsp";
}
}
8、编写ShiroConfig
@Configuration
public class ShiroConfig {
//1.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map map = new HashMap();
// anon 设置为公共资源,放行要注意anon和authc的顺序
map.put("/toIndex","anon");
map.put("/toLogin","anon");
map.put("/register","anon");
map.put("/toRegister","anon");
map.put("/","authc");
map.put("/index","authc"); //authc 请求这个资源需要认证和授权
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}
//创建realm对象
@Bean
public UserRealm userRealm(){...}
}
public interface UserService {
void register(User user);
}
(2)UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public void register(User user) {
// 生成随机盐
String salt = SaltUtil.getSalt(ShiroConstant.SALT_LENGTH);
// 保存随机盐
user.setSalt(salt);
// 生成密码
Md5Hash password = new Md5Hash(user.getPassword(), salt, ShiroConstant.HASH_ITERATORS);
// 保存密码
user.setPassword(password.toHex());
userMapper.insert(user);
}
}
(3)SaltUtil
public class SaltUtil {
public static String getSalt(int n){
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
char aChar = chars[new Random().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}
}
(4)ShiroConstant
public class ShiroConstant {
public static final int SALT_LENGTH = 8;
public static final int HASH_ITERATORS = 1024;
public interface HASH_ALGORITHM_NAME {
String MD5 = "MD5";
}
}
7、编写Controller
@Controller
public class MyController {
@Autowired
private UserService userService;
@RequestMapping("/toLogin")
public String toLogin(){...}
@RequestMapping("/toRegister")
public String toRegister(){...}
@RequestMapping("/toIndex")
public String toLogin(){...}
@RequestMapping("/login")
public String login(String username,String password){...}
@RequestMapping("/register")
public String register(User user){
try {
userService.register(user);
return "redirect:/login.jsp";
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/register.jsp";
}
}
8、编写ShiroConfig
@Configuration
public class ShiroConfig {
//1.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map map = new HashMap();
// anon 设置为公共资源,放行要注意anon和authc的顺序
map.put("/toIndex","anon");
map.put("/toLogin","anon");
map.put("/register","anon");
map.put("/toRegister","anon");
map.put("/","authc");
map.put("/index","authc"); //authc 请求这个资源需要认证和授权
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}
//创建realm对象
@Bean
public UserRealm userRealm(){...}
}
public class SaltUtil {
public static String getSalt(int n){
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
char aChar = chars[new Random().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}
}
(4)ShiroConstant
public class ShiroConstant {
public static final int SALT_LENGTH = 8;
public static final int HASH_ITERATORS = 1024;
public interface HASH_ALGORITHM_NAME {
String MD5 = "MD5";
}
}
7、编写Controller
@Controller
public class MyController {
@Autowired
private UserService userService;
@RequestMapping("/toLogin")
public String toLogin(){...}
@RequestMapping("/toRegister")
public String toRegister(){...}
@RequestMapping("/toIndex")
public String toLogin(){...}
@RequestMapping("/login")
public String login(String username,String password){...}
@RequestMapping("/register")
public String register(User user){
try {
userService.register(user);
return "redirect:/login.jsp";
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/register.jsp";
}
}
8、编写ShiroConfig
@Configuration
public class ShiroConfig {
//1.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map map = new HashMap();
// anon 设置为公共资源,放行要注意anon和authc的顺序
map.put("/toIndex","anon");
map.put("/toLogin","anon");
map.put("/register","anon");
map.put("/toRegister","anon");
map.put("/","authc");
map.put("/index","authc"); //authc 请求这个资源需要认证和授权
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}
//创建realm对象
@Bean
public UserRealm userRealm(){...}
}
@Controller
public class MyController {
@Autowired
private UserService userService;
@RequestMapping("/toLogin")
public String toLogin(){...}
@RequestMapping("/toRegister")
public String toRegister(){...}
@RequestMapping("/toIndex")
public String toLogin(){...}
@RequestMapping("/login")
public String login(String username,String password){...}
@RequestMapping("/register")
public String register(User user){
try {
userService.register(user);
return "redirect:/login.jsp";
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/register.jsp";
}
}
8、编写ShiroConfig
@Configuration
public class ShiroConfig {
//1.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map map = new HashMap();
// anon 设置为公共资源,放行要注意anon和authc的顺序
map.put("/toIndex","anon");
map.put("/toLogin","anon");
map.put("/register","anon");
map.put("/toRegister","anon");
map.put("/","authc");
map.put("/index","authc"); //authc 请求这个资源需要认证和授权
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}
//创建realm对象
@Bean
public UserRealm userRealm(){...}
}
重启项目测试:可以看到注册的系用户保存到数据库的密码是经过加密的
三、MD5、Salt的认证
1、编写Service层
public interface UserService {
……省略其他方法……
User findUserByUserName(String userName);
}
@Service("userService")
public class UserServiceImpl implements UserService {
……省略其他方法……
@Override
public User findUserByUserName(String userName) {
return userMapper.findUserByUsername(userName);
}
}
2、编写UserRealm
public class UserRealm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取当前登录的用户名
String principal = (String) token.getPrincipal();
// 由于CustomerRealm并没有交由工厂管理,故不能诸如UserService
UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
User user = userService.findUserByUserName(principal);
if(!ObjectUtils.isEmpty(user)){
return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), new CustomerByteSource(user.getSalt()),this.getName());
}
return null;
}
}
3、编写ApplicationContextUtil
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
public static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
public static Object getBean(String beanName){
return context.getBean(beanName);
}
}
4、编写ShiroConfig
@Configuration
public class ShiroConfiguration {
……省略其他方法……
@Bean
public UserRealm getRealm(){
UserRealm userRealm = new UserRealm();
// 设置密码匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
// 设置加密方式
credentialsMatcher.setHashAlgorithmName(ShiroConstant.HASH_ALGORITHM_NAME.MD5);
// 设置散列次数
credentialsMatcher.setHashIterations(ShiroConstant.HASH_ITERATORS);
customerRealm.setCredentialsMatcher(credentialsMatcher);
return uerRealm;
}
}
public interface UserService {
……省略其他方法……
User findUserByUserName(String userName);
}
@Service("userService")
public class UserServiceImpl implements UserService {
……省略其他方法……
@Override
public User findUserByUserName(String userName) {
return userMapper.findUserByUsername(userName);
}
}
2、编写UserRealm
public class UserRealm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取当前登录的用户名
String principal = (String) token.getPrincipal();
// 由于CustomerRealm并没有交由工厂管理,故不能诸如UserService
UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
User user = userService.findUserByUserName(principal);
if(!ObjectUtils.isEmpty(user)){
return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), new CustomerByteSource(user.getSalt()),this.getName());
}
return null;
}
}
3、编写ApplicationContextUtil
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
public static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
public static Object getBean(String beanName){
return context.getBean(beanName);
}
}
4、编写ShiroConfig
@Configuration
public class ShiroConfiguration {
……省略其他方法……
@Bean
public UserRealm getRealm(){
UserRealm userRealm = new UserRealm();
// 设置密码匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
// 设置加密方式
credentialsMatcher.setHashAlgorithmName(ShiroConstant.HASH_ALGORITHM_NAME.MD5);
// 设置散列次数
credentialsMatcher.setHashIterations(ShiroConstant.HASH_ITERATORS);
customerRealm.setCredentialsMatcher(credentialsMatcher);
return uerRealm;
}
}
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
public static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
public static Object getBean(String beanName){
return context.getBean(beanName);
}
}
4、编写ShiroConfig
@Configuration
public class ShiroConfiguration {
……省略其他方法……
@Bean
public UserRealm getRealm(){
UserRealm userRealm = new UserRealm();
// 设置密码匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
// 设置加密方式
credentialsMatcher.setHashAlgorithmName(ShiroConstant.HASH_ALGORITHM_NAME.MD5);
// 设置散列次数
credentialsMatcher.setHashIterations(ShiroConstant.HASH_ITERATORS);
customerRealm.setCredentialsMatcher(credentialsMatcher);
return uerRealm;
}
}
重启项目测试:可以看到账号都能登录
四、Shiro基于角色授权
1、创建表
# 之前已经创建过用户表了,这里就不创建了:t_user
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(8) DEFAULT NULL,
`role_id` int(8) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
# 之前已经创建过用户表了,这里就不创建了:t_user DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(64) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(8) DEFAULT NULL, `role_id` int(8) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
t_user
t_role
t_user_role
2、编写User和Role的实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User{
private List roles = new ArrayList<>();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role{
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
}
3、编写Mapper层
@Mapper
public interface UserMapper extends baseMapper {
@Select("SELECT u.id,u.username,u.password,u.salt FROM t_user u WHERe u.username = #{username}")
User findUserByUsername(String username);
}
@Mapper
public interface RoleMapper extends baseMapper {
@Select("select r.id,r.name from t_role r left join t_user_role ur on ur.role_id = r.id where ur.user_id = #{userId}")
List getRolesByUserId(Integer userId);
}
4、编写Service层
@Mapper public interface UserMapper extends baseMapper{ @Select("SELECT u.id,u.username,u.password,u.salt FROM t_user u WHERe u.username = #{username}") User findUserByUsername(String username); }
@Mapper public interface RoleMapper extends baseMapper{ @Select("select r.id,r.name from t_role r left join t_user_role ur on ur.role_id = r.id where ur.user_id = #{userId}") List getRolesByUserId(Integer userId); }
4、编写Service层
新建RoleService和RoleServiceImpl
public interface RoleService {
List getRolesByUserId(Integer userId);
}
@Service("roleService")
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleMapper roleMapper;
@Override
public List getRolesByUserId(Integer userId) {
return roleMapper.getRolesByUserId(userId);
}
}
5、Realm中实现授权
public class UserRealm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 获取主身份信息
String principal = (String) principals.getPrimaryPrincipal();
// 根据用户信息
UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
User user = userService.findUserByUserName(principal);
//根据用户id获取角色信息
RoleService roleService = (RoleService) ApplicationContextUtil.getBean("roleService");
List roles = roleService.getRolesByUserId(user.getId());
//如果角色信息不为空则添加角色信息
if(!CollectionUtils.isEmpty(roles)){
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
roles.forEach(role -> {
simpleAuthorizationInfo.addRole(role.getName());
});
return simpleAuthorizationInfo;
}
return null;
}
}
6、编写Index页面
编写页面前请导入如下的依赖
com.github.theborakompanioni
thymeleaf-extras-shiro
2.0.0
Title
系统主页
<%--需要引入:xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro"--%>
<%-- admin角色的用户能同时拥有用户管理和订单管理的权限,user角色的用户只拥有订单管理的权限 --%>
- 订单管理
- 用户管理
重启项目测试
五、Shiro基于权限的授权
1、新建表新增t_perm和t_role_permn表
DROp TABLE IF EXISTS `t_perms`;
CREATE TABLE `t_perms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_role_perms`;
CREATE TABLE `t_role_perms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) DEFAULT NULL,
`perms_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
DROp TABLE IF EXISTS `t_perms`; CREATE TABLE `t_perms` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(128) DEFAULT NULL, `url` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `t_role_perms`; CREATE TABLE `t_role_perms` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_id` int(11) DEFAULT NULL, `perms_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
t_perms
t_role_perms
2、编写Role和Perms实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
private List permissions = new ArrayList<>();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Perms{
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private String url;
}
3、编写Mapper层
@Mapper
public interface PermsMapper extends baseMapper {
@Select("select p.id,p.name,p.url from t_perms p left join t_role_perms rp on rp.perms_id = p.id where rp.role_id = #{roleId}")
List getPermssByRoleId(Integer roleId);
}
4、编写Service层
public interface PermsService {
List getPermsByRoleId(Integer roleId);
}
@Service("permissionService")
public class PermsServiceImpl implements PermsService {
@Autowired
private PermsMapper permsMapper;
@Override
public List getPermssByRoleId(Integer roleId) {
return permsMapper.getPermssByRoleId(roleId);
}
}
5、编写userRealm
public class UserRealm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 获取主身份信息
String principal = (String) principals.getPrimaryPrincipal();
// 根据主身份信息获取角色信息
UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
User user = userService.findUserByUserName(principal);
RoleService roleService = (RoleService) ApplicationContextUtil.getBean("roleService");
List roles = roleService.getRolesByUserId(user.getId());
if(!CollectionUtils.isEmpty(roles)){
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
roles.forEach(role -> {
simpleAuthorizationInfo.addRole(role.getName());
PermissionService permissionService = (PermissionService) ApplicationContextUtil.getBean("permissionService");
List permissions = permissionService.getPermissionsByRoleId(role.getId());
if(!CollectionUtils.isEmpty(permissions)){
permissions.forEach(permission -> {
simpleAuthorizationInfo.addStringPermission(permission.getName());
});
}
});
return simpleAuthorizationInfo;
}
return null;
}
}
6、编写Index页面
Title
系统主页
<%--需要引入:xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro"--%>
<%-- admin角色的用户能同时拥有用户管理和订单管理的权限,user角色的用户只拥有订单管理的权限 --%>
- 订单管理
- 用户管理
增加
修改
删除
查询
public class UserRealm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 获取主身份信息
String principal = (String) principals.getPrimaryPrincipal();
// 根据主身份信息获取角色信息
UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
User user = userService.findUserByUserName(principal);
RoleService roleService = (RoleService) ApplicationContextUtil.getBean("roleService");
List roles = roleService.getRolesByUserId(user.getId());
if(!CollectionUtils.isEmpty(roles)){
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
roles.forEach(role -> {
simpleAuthorizationInfo.addRole(role.getName());
PermissionService permissionService = (PermissionService) ApplicationContextUtil.getBean("permissionService");
List permissions = permissionService.getPermissionsByRoleId(role.getId());
if(!CollectionUtils.isEmpty(permissions)){
permissions.forEach(permission -> {
simpleAuthorizationInfo.addStringPermission(permission.getName());
});
}
});
return simpleAuthorizationInfo;
}
return null;
}
}
6、编写Index页面
Title
系统主页
<%--需要引入:xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro"--%>
<%-- admin角色的用户能同时拥有用户管理和订单管理的权限,user角色的用户只拥有订单管理的权限 --%>
- 订单管理
- 用户管理
重启项目测试
六、EhCache实现缓存
目前还在学习中...
如果哪里有错误还望有大佬指明一下,轻点喷



