一、概述

本博客主要讲解spring boot整合Apache的shiro框架,实现基于角色的安全访问控制或者基于权限的访问安全控制,其中还使用到分布式缓存redis进行用户认证信息的缓存,减少数据库查询的开销。Apache shiro与spring security的作用几乎一样都是简化了Java程序的权限控制开发。

二、项目

2.1首先是通过eclipse创建一个最新的spring boot项目,并添加以下依赖:

pom.xml

 复制<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>net.xqlee.project.demo.shiro</groupId>
<artifactId>demo-springboot-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>demo-springboot-shiro-hello</name>
<description>demo-springboot-shiro-hello</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- shiro权限控制框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.3.2</version>
</dependency>
<!--缓存暂时用简单的 https://mvnrepository.com/artifact/org.ehcache/ehcache -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<!-- redis缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

2.2配置redis

application.properties文件中添加配置:

 复制####################Redis 配置信息 ##########################
# Redis数据库分片索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=10.1.1.2
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0 #测试redis的缓存日志
logging.level.net.xqlee.project.demo.shiro.config.shiro.cache=DEBUG

Java config的redis配置
RedisConfig

 复制package net.xqlee.project.demo.shiro.config.redis;

import java.lang.reflect.Method;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; @Configuration
@EnableCaching // 继承CachingConfigurerSupport并重写方法,配合该注解实现spring缓存框架的启用
public class RedisConfig extends CachingConfigurerSupport {
/** 载入通过配置文件配置的连接工场 **/
@Autowired
RedisConnectionFactory redisConnectionFactory; @SuppressWarnings("rawtypes")
@Autowired
RedisTemplate redisTemplate; @Bean
RedisTemplate<String, Object> objRedisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
} /*
* (non-Javadoc)
*
* @see org.springframework.cache.annotation.CachingConfigurerSupport#
* cacheManager()
*/
@Bean // 必须添加此注解
@Override
public CacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
// 设置缓存过期时间
// redisCacheManager.setDefaultExpiration(60);//秒
return redisCacheManager;
} /**
* 重写缓存的key生成策略,可根据自身业务需要进行自己的配置生成条件
*
* @see org.springframework.cache.annotation.CachingConfigurerSupport#
* keyGenerator()
*/
@Bean // 必须项
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
} }

2.3创建shiro需要的 redis缓存器和缓存管理实现类

首先是缓存器cache的实现
RedisCache.java

 复制package net.xqlee.project.demo.shiro.config.shiro.cache;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit; import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate; /**
* Redis的Shiro缓存对象实现
*
* @author xq
*
* @param <K>
* @param <V>
*/
public class RedisCache<K, V> implements Cache<K, V> {
private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
private RedisTemplate<K, V> redisTemplate;
private final static String PREFIX = "shiro-cache:";
private String cacheKey;
private long globExpire = 30; @SuppressWarnings({ "rawtypes", "unchecked" })
public RedisCache(final String name, final RedisTemplate redisTemplate) {
this.cacheKey = PREFIX + name + ":";
this.redisTemplate = redisTemplate;
} @Override
public V get(K key) throws CacheException {
logger.debug("Shiro从缓存中获取数据KEY值["+key+"]");
redisTemplate.boundValueOps(getCacheKey(key)).expire(globExpire, TimeUnit.MINUTES);
return redisTemplate.boundValueOps(getCacheKey(key)).get();
} @Override
public V put(K key, V value) throws CacheException {
V old = get(key);
redisTemplate.boundValueOps(getCacheKey(key)).set(value);
return old;
} @Override
public V remove(K key) throws CacheException {
V old = get(key);
redisTemplate.delete(getCacheKey(key));
return old;
} @Override
public void clear() throws CacheException {
redisTemplate.delete(keys()); } @Override
public int size() {
return keys().size();
} @Override
public Set<K> keys() {
return redisTemplate.keys(getCacheKey("*"));
} @Override
public Collection<V> values() {
Set<K> set = keys();
List<V> list = new ArrayList<>();
for (K s : set) {
list.add(get(s));
}
return list;
} @SuppressWarnings("unchecked")
private K getCacheKey(Object k) {
return (K) (this.cacheKey + k);
}
}

还有缓存管理器:
RedisCacheManager.java

 复制package net.xqlee.project.demo.shiro.config.shiro.cache;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; /**
* Redis的Shiro缓存管理器实现
*
* @author xq
*
*/
public class RedisCacheManager implements CacheManager {
@Autowired
private RedisTemplate<String, Object> redisTemplate; @Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
return new RedisCache<>(name, redisTemplate);
} }

2.4自定义一个shiro的realm实现

创建realm之前需要编写一个模拟数据库查询的用户业务处理类,提供给上面的自定义realm使用

简单的用户登录对象:

 复制package net.xqlee.project.demo.shiro.pojo;

import java.util.Date;
import java.util.List; /**
* 用户信息
*
* @author xqlee
*
*/
public class LoginAccount {
/** 用户名 */
String loginName;
List<String> roles;// 测试用
List<String> permissions;// 测试用直接放用户登录对象里面
/** 用户密码 **/
String password;
boolean enabled;
Date createDate;
boolean isExpired; public String getLoginName() {
return loginName;
} public void setLoginName(String loginName) {
this.loginName = loginName;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public boolean isEnabled() {
return enabled;
} public void setEnabled(boolean enabled) {
this.enabled = enabled;
} public Date getCreateDate() {
return createDate;
} public void setCreateDate(Date createDate) {
this.createDate = createDate;
} public boolean isExpired() {
return isExpired;
} public void setExpired(boolean isExpired) {
this.isExpired = isExpired;
} public List<String> getRoles() {
return roles;
} public void setRoles(List<String> roles) {
this.roles = roles;
} public List<String> getPermissions() {
return permissions;
} public void setPermissions(List<String> permissions) {
this.permissions = permissions;
} }

用户模拟业务处理

 复制package net.xqlee.project.demo.shiro.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.springframework.stereotype.Component; import net.xqlee.project.demo.shiro.pojo.LoginAccount; /**
* 用户业务服务类
*
* @author xqlee
*
*/
@Component("userService")
public class UserService {
/** 由于重点不在数据库,这里需要使用数据库的地方全部用map代替 **/
/** 用户信息 **/
static Map<String, LoginAccount> users = new HashMap<>(); static {
// 创建一个用户
LoginAccount account = new LoginAccount();
account.setLoginName("leftso");
account.setPassword("123456");
account.setEnabled(true);
account.setExpired(false); // 角色添加
List<String> roles = new ArrayList<>();
roles.add("ROLE_USER");
account.setRoles(roles); List<String> permissions = new ArrayList<>();
permissions.add("query");
permissions.add("delete"); account.setPermissions(permissions);
users.put(account.getLoginName(), account); // 创建一个用户
LoginAccount admin = new LoginAccount();
admin.setLoginName("admin");
admin.setPassword("123456");
admin.setEnabled(true);
admin.setExpired(false); // 角色添加
roles = new ArrayList<>();
roles.add("ROLE_ADMIN");
admin.setRoles(roles); permissions = new ArrayList<>();
permissions.add("query");
permissions.add("delete"); admin.setPermissions(permissions); users.put("admin", admin); } /**
* 通过用户名获取用户权限集合
*
* @param loginName
* 用户名
* @return 用户的权限集合
*/
public List<String> getPermissionsByLoginName(String loginName) { if (users.containsKey(loginName)) {
return users.get(loginName).getPermissions();
}
return new ArrayList<>(); } /**
* 通过用户名获取用户信息
*
* @param loginName
* 用户名
* @return 用户信息
*/
public LoginAccount getLoginAccountByLoginName(String loginName) {
if (users.containsKey(loginName)) {
return users.get(loginName);
}
return null; }
}
 复制package net.xqlee.project.demo.shiro.config.shiro;

import java.util.List;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import net.xqlee.project.demo.shiro.pojo.LoginAccount;
import net.xqlee.project.demo.shiro.service.UserService; /**
* 实现一个基于JDBC的Realm,继承AuthorizingRealm可以看见需要重写两个方法,doGetAuthorizationInfo和doGetAuthenticationInfo
*
* @author xqlee
*
*/
@Component("JDBCShiroRealm")
public class JDBCShiroRealm extends AuthorizingRealm {
private static final Logger logger = LoggerFactory.getLogger(JDBCShiroRealm.class); /*** 用户业务处理类,用来查询数据库中用户相关信息 ***/
@Autowired
UserService userService; /***
* 获取用户授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.info("##################执行Shiro权限认证##################");
// 获取用户名
String loginName = (String) principalCollection.fromRealm(getName()).iterator().next();
// 判断用户名是否存在
if (StringUtils.isEmpty(loginName)) {
return null;
}
// 查询登录用户信息
LoginAccount account = userService.getLoginAccountByLoginName(loginName);
if (account == null) {
logger.warn("用户[" + loginName + "]信息不存在");
return null;
}
// 创建一个授权对象
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 进行权限设置
List<String> permissions = account.getPermissions();
if (permissions != null && !permissions.isEmpty()) {
info.addStringPermissions(permissions);
}
// 角色设置
List<String> roles = account.getRoles();
if (roles != null) {
info.addRoles(roles);
} return info;
} /**
* 获取用户认证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
logger.info("##################执行Shiro登陆认证##################");
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
// 通过表单接收的用户名
String loginName = token.getUsername();
if (loginName != null && !"".equals(loginName)) {
// 模拟数据库查询用户信息
LoginAccount account = userService.getLoginAccountByLoginName(loginName); if (account != null) {
// 登陆的主要信息: 可以是一个实体类的对象, 但该实体类的对象一定是根据 token 的 username 查询得到的.
Object principal = token.getPrincipal();
// 创建shiro的用户认证对象
// 注意该对象的密码将会传递至后续步骤与前面登陆的subject的密码进行比对。
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal,
account.getPassword(), getName()); return authenticationInfo;
}
}
return null;
} }

2.5shiro的核心配置文件

ShiroConfig.java

 复制package net.xqlee.project.demo.shiro.config.shiro;

import java.util.LinkedHashMap;
import java.util.Map; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
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 net.xqlee.project.demo.shiro.config.shiro.cache.RedisCacheManager; /***
* shiro权限管理配置
*
* @author xqlee
*
*/
@Configuration
public class ShiroConfig {
/**
* ehcache缓存方案<br/>
* 简单的缓存,后续可更换为redis缓存,通过自己实现shiro的CacheManager接口和Cache接口
*
* @return
*/
@Bean
public CacheManager shiroEhCacheManager() {
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return cacheManager;
} /**
* redis缓存方案
*
* @return
*/
@Bean
public CacheManager shiroRedisCacheManager() {
return new RedisCacheManager();
} /****
* 自定义Real
*
* @return
*/
@Bean
public JDBCShiroRealm jdbcShiroRealm() {
JDBCShiroRealm realm = new JDBCShiroRealm();
// 根据情况使用缓存器
realm.setCacheManager(shiroRedisCacheManager());//shiroEhCacheManager()
return realm;
} /***
* 安全管理配置
*
* @return
*/
@Bean
public SecurityManager defaultWebSecurityManager() {
// DefaultSecurityManager defaultSecurityManager = new
// DefaultSecurityManager();
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 注意:!!!初始化成这个将会报错java.lang.IllegalArgumentException:
// SessionContext must be an HTTP compatible
// implementation.:模块化本地测试shiro的一些总结
// 配置
securityManager.setRealm(jdbcShiroRealm());
// 注意这里必须配置securityManager
SecurityUtils.setSecurityManager(securityManager);
// 根据情况选择缓存器
securityManager.setCacheManager(shiroRedisCacheManager());//shiroEhCacheManager() return securityManager;
} /**
* 配置shiro的拦截器链工厂,默认会拦截所有请求,并且不可配置
*
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
// 配置安全管理(必须)
filterFactoryBean.setSecurityManager(defaultWebSecurityManager());
// 配置登陆的地址
filterFactoryBean.setLoginUrl("/userNoLogin.do");// 未登录时候跳转URL,如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
filterFactoryBean.setSuccessUrl("/welcome.do");// 成功后欢迎页面
filterFactoryBean.setUnauthorizedUrl("/403.do");// 未认证页面 // 配置拦截地址和拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 必须使用LinkedHashMap,因为拦截有先后顺序
// authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问 filterChainDefinitionMap.put("/userNoLogin.do*", "anon");// 未登录跳转页面不设权限认证
filterChainDefinitionMap.put("/login.do*", "anon");// 登录接口不设置权限认真
filterChainDefinitionMap.put("/logout.do*", "anon");// 登出不需要认证 // 以下配置同样可以通过注解
// @RequiresPermissions("user:edit")来配置访问权限和角色注解@RequiresRoles(value={"ROLE_USER"})方式定义
// 权限配置示例,这里的配置理论来自数据库查询
filterChainDefinitionMap.put("/user/**", "roles[ROLE_USER],perms[query]");// /user/下面的需要ROLE_USER角色或者query权限才能访问
filterChainDefinitionMap.put("/admin/**", "perms[ROLE_ADMIN]");// /admin/下面的所有需要ROLE_ADMIN的角色才能访问 // 剩下的其他资源地址全部需要用户认证后才能访问
filterChainDefinitionMap.put("/**", "authc");
filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); // 全部配置
// anon org.apache.shiro.web.filter.authc.AnonymousFilter 匿名访问
//
// authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
// 需要登录,不需要权限和角色可访问
//
// authcBasic
// org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
//
// perms
// org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
// 需要给定的权限值才能访问
//
// port org.apache.shiro.web.filter.authz.PortFilter
//
// rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
//
// roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
// 需要给定的角色才能访问
//
// ssl org.apache.shiro.web.filter.authz.SslFilter
//
// user org.apache.shiro.web.filter.authc.UserFilter
//
// logout org.apache.shiro.web.filter.authc.LogoutFilter
return filterFactoryBean;
} }

上面配置中有两个缓存器可以选择,一个是简单的ehcache,一个是redis,大型项目推荐使用redis

2.6编写一个测试的controller

 复制package net.xqlee.project.demo.shiro.controller;

import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import net.sf.json.JSONObject; /**
* 用户登录用
*
* @author xqlee
*
*/
@RestController
public class LoginController {
private static final Logger logger = LoggerFactory.getLogger(LoginController.class); /****
* 用户未登录
*
* @return
*/
@GetMapping("userNoLogin.do")
public Object noLogin() {
JSONObject object = new JSONObject();
object.put("message", "用户未登录");
return object;
} @GetMapping(value = "/login.do")
public String login(String loginName, String password) {
try {
// 创建shiro需要的token
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginName, password.toCharArray());
usernamePasswordToken.setRememberMe(true);// 记住 try {
SecurityUtils.getSubject().login(usernamePasswordToken);
} catch (UnknownAccountException uae) {
logger.info("对用户[" + loginName + "]进行登录验证..验证未通过,未知账户");
return "对用户[" + loginName + "]进行登录验证..验证未通过,未知账户";
} catch (IncorrectCredentialsException ice) {
logger.info("对用户[" + loginName + "]进行登录验证..验证未通过,错误的凭证");
ice.printStackTrace();
return "对用户[" + loginName + "]进行登录验证..验证未通过,错误的凭证";
} catch (LockedAccountException lae) {
logger.info("对用户[" + loginName + "]进行登录验证..验证未通过,账户已锁定");
return "对用户[" + loginName + "]进行登录验证..验证未通过,账户已锁定";
} catch (ExcessiveAttemptsException eae) {
logger.info("对用户[" + loginName + "]进行登录验证..验证未通过,错误次数过多");
return "对用户[" + loginName + "]进行登录验证..验证未通过,错误次数过多";
} catch (AuthenticationException ae) {
// 通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
logger.info("对用户[" + loginName + "]进行登录验证..验证未通过,堆栈轨迹如下");
ae.printStackTrace();
return "用户名或密码不正确";
}
return "Login Success!";
} catch (Exception e) {
return "登陆时候发生异常," + e.getMessage();
}
} @GetMapping("/user/hello.do")
public String hello() {
return "Hello User, From Server";
} @GetMapping("/admin/hello.do")
public String helloAdmin() {
return "Hello Admin, From Server";
} @GetMapping("/welcome.do")
public String loginSuccess() {
return "welcome";
} @GetMapping("/403.do")
public Object error403(HttpServletResponse response) {
response.setStatus(403);
JSONObject object = new JSONObject();
object.put("message", "用户权限不够");
return object;
} }

2.7测试

1.通过spring bootapplication方式启动项目,项目默认监听在8080端口

首先访问需要权限的url  http://localhost:8080/user/hello.do


可以看到返回的是用户未登录提示,也就是我们在controller中写的未登录时候调用的方法返回值。

现在我们先通过用户名leftso和密码123456进行登录  localhost:8080/login.do?loginName=leftso&password=123456

可以看到登录成功,这个时候我们再次打开最初访问的:http://localhost:8080/user/hello.do

可以看到这次我们成功访问了需要ROLE_USER角色的url,

现在用这个登录的信息访问需要ROLE_ADMIN权限的地址http://localhost:8080/admin/hello.do


上面可以看到,无法访问,返回的提示是权限不足

切换为admin的用户登录,然后访问地址http://localhost:8080/admin/hello.do

首先是admin登录

然后访问admin权限的地址


上面看到admin也对应的访问成功了。

并且,切回eclipse的控制台可以看到:

我们的redis缓存也起作用了。

至此spring boot shiro redis的整合角色和权限控制讲解完毕。

spring boot shiro redis整合基于角色和权限的安全管理-Java编程的更多相关文章

  1. spring boot Shiro JWT整合

    一个api要支持H5, PC和APP三个前端,如果使用session的话对app不是很友好,而且session有跨域攻击的问题,所以选择了JWT 1.导入依赖包 <dependency> ...

  2. SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

    SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建 技术栈 : SpringBoot + shiro + jpa + freemark ,因为篇幅原因,这里只 ...

  3. Spring Boot 2.x整合Redis

    最近在学习Spring Boot 2.x整合Redis,在这里和大家分享一下,希望对大家有帮助. Redis是什么 Redis 是开源免费高性能的key-value数据库.有以下的优势(源于Redis ...

  4. Spring Boot 2.x 整合 Redis最佳实践

    一.前言 在前面的几篇文章中简单的总结了一下Redis相关的知识.本章主要讲解一下 Spring Boot 2.0 整合 Redis.Jedis 和 Lettuce 是 Java 操作 Redis 的 ...

  5. 15套java架构师、集群、高可用、高可扩展、高性能、高并发、性能优化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战视频教程

    * { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩展. ...

  6. (39.2). Spring Boot Shiro权限管理【从零开始学Spring Boot】

    (本节提供源代码,在最下面可以下载) (4). 集成Shiro 进行用户授权 在看此小节前,您可能需要先看: http://412887952-qq-com.iteye.com/blog/229973 ...

  7. Spring Boot 2.X整合Spring-cache,让你的网站速度飞起来

    计算机领域有人说过一句名言:“计算机科学领域的任何问题都可以通过增加一个中间层来解决”,今天我们就用Spring-cache给网站添加一层缓存,让你的网站速度飞起来. 本文目录 一.Spring Ca ...

  8. Spring Boot 2.0 整合携程Apollo配置中心

    原文:https://www.jianshu.com/p/23d695af7e80 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够 ...

  9. Spring Boot Shiro

    Shiro 核心 API Subject:用户主体(每次请求都会创建Subject). principal:代表身份.可以是用户名.邮件.手机号码等等,用来标识一个登录主体的身份. credentia ...

随机推荐

  1. Java Web开发技术教程入门-JSP基本语法和九大内置对象

    这两天气温逐渐升高,好想把自己泡在冰块里······ 恩嗯摁蒽恩嗯摁蒽恩嗯摁蒽恩嗯摁蒽.......今天阅读到了这本书的第四章-JSP基本语法.经过第一天的阅读,我们明白JSP技术是Java Web开 ...

  2. <form:select>

    <form:select path="classification" class="input-medium"> <form:option v ...

  3. C++11随机数的正确打开方式

    C++11随机数的正确打开方式 在C++11之前,现有的随机数函数都存在一个问题:在利用循环多次获取随机数时,如果程序运行过快或者使用了多线程等方法,srand((unsigned)time(null ...

  4. eclipse控制台输出太多被顶掉问题

    控制台空白处右键 属性

  5. AQtime使用

    今天刚到网上下了AQtime.因为有个通信及数据存储的程序出现的内存泄漏.在用户的环境里出现了两次,在测试的环境里一次也没有出现,开发人员猜测是一部分代码引起的.说要代码的覆盖测试.看看测试环境里有那 ...

  6. 基于AliOS的车载小程序

    4月16日上海国际车展首日,阿里巴巴表示正在研发基于AliOS的车载小程序.同时还展出AI HUD.AI驾驶舱等最新技术,AliOS表示正在构建一个可持续发展的整合平台. 阿里方面表示,作为小程序在车 ...

  7. ceph分布式存储简介

    一.Ceph简介: 什么是分布式存储? 我在一个环境当中,有很多很多的服务器,服务器上也有它自己很多的硬盘,我通过软件的形式把若干服务器都收集起来,部署成一个软件,在这个逻辑的软件里可以同时看到我若干 ...

  8. u-boot log_init函数分析

    log_init, int log_init(void){    struct log_driver *drv = ll_entry_start(struct log_driver, log_driv ...

  9. Spring mvc项目的web.xml以及注释

    web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp ...

  10. java常用关键词关键字,方法源码解析

    transient volatile native final Integer String Class &&Object newInstance Class.forName,Clas ...