来自:blog.csdn.net/to10086/article/details/109573948
一、微服务权限设计
二、设计方案
方案一
三、具体实现
3.1 项目的结构如下:
common模块: 整个项目的公共模块, common-core
就包含了其他微服务需要的一些常量数据、返回值、异常,common-cache
模块中包含了所有微服务需要的shrio缓存配置,除了用户服务其他服务需要的授权模块common-auth
。
gateway-service服务: 网关服务,所有其他服务的入口。 user-api: 用户服务定义的数据接口。 user-provider-service: 用户服务接口的实现,用户服务的提供者。 user-consumer-service: 用户服务的最外层,供nginx访问调用的服务,用户服务的消费者。 video-api: 同用户服务api。 video-provider: 同用户服务provider。 video-consumer: 同用户服务consumer。
3.2 表关系如下
3.3 共享session会话(缓存模块common-cache)
3.3.1 为什么需要共享session?
3.3.2 怎么实现共享session?
DefaultWebSecurityManager
,我们看一下实例化这个安全管理器类中间有哪些组件会被初始化。DefaultWebSecurityManager
的构造器。public DefaultWebSecurityManager() {
super();
((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(new DefaultWebSessionStorageEvaluator());
this.sessionMode = HTTP_SESSION_MODE;
setSubjectFactory(new DefaultWebSubjectFactory());
setRememberMeManager(new CookieRememberMeManager());
setSessionManager(new ServletContainerSessionManager());
}
DefaultWebSecurityManager
的父类DefaultSecurityManager
,查看DefaultSecurityManager
的构造器。public DefaultSecurityManager() {
super();
this.subjectFactory = new DefaultSubjectFactory();
this.subjectDAO = new DefaultSubjectDAO();
}
DefaultSecurityManager
的父类SessionsSecurityManager
,查看SessionsSecurityManager
的构造器。public SessionsSecurityManager() {
super();
this.sessionManager = new DefaultSessionManager();
applyCacheManagerToSessionManager();
}
DefaultSessionManager
。我们点进去看看。可以看到DefaultSessionManager
中默认的就是使用的是内存来保存session(MemorySessionDAO
就是对session进行操作的类)。public DefaultSessionManager() {
this.deleteInvalidSessions = true;
this.sessionFactory = new SimpleSessionFactory();
this.sessionDAO = new MemorySessionDAO();
}
SessionDAO
来覆盖默认的MemorySessionDAO
,下面来看看怎么实现自定义的SessionDAO
。AbstractSessionDAO
主要有两个子类,一个是已经实现好的EnterpriseCacheSessionDAO
,另一个就是MemorySessionDAO
,现在我们需要替换默认的MemorySessionDAO
,要么我们继承AbstractSessionDAO
实现其中的读写session的方法,要么直接使用它已经给我们实现好的EnterpriseCacheSessionDAO
。EnterpriseCacheSessionDAO
类。public EnterpriseCacheSessionDAO() {
setCacheManager(new AbstractCacheManager() {
@Override
protected Cache<Serializable, Session> createCache(String name) throws CacheException {
return new MapCache<Serializable, Session>(name, new ConcurrentHashMap<Serializable, Session>());
}
});
}
AbstractCacheManager
缓存管理器,并且使用的是ConcurrentHashMap
来保存会话session,因此如果我们要用这个EnterpriseCacheSessionDAO
类来实现缓存操作,那么我们就需要需要写一个自定义的CacheManager
来覆盖它默认的CacheManager
。3.3.3 具体实现
首先导入我们需要的依赖包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--导入shrio相关-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
编写我们自己的CacheManager
@Component("myCacheManager")
public class MyCacheManager implements CacheManager {
@Override
public <K, V> Cache<K, V> getCache(String s) throws CacheException {
return new MyCache();
}
}
Jedis客户端
public class JedisClient {
private static Logger logger = LoggerFactory.getLogger(JedisClient.class);
protected static final ThreadLocal<Jedis> threadLocalJedis = new ThreadLocal<Jedis>();
private static JedisPool jedisPool;
private static final String HOST = "localhost";
private static final int PORT = 6379;
private static final String PASSWORD = "1234";
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 16;
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = -1;
//超时时间
private static final int TIMEOUT = 1000 * 5;
//等待可用连接的最大时间,单位毫秒,默认值为-1。表示用不超时
private static int MAX_WAIT = 1000 * 5;
// 连接数据库(0-15)
private static final int DATABASE = 2;
static {
initialPool();
}
public static JedisPool initialPool() {
JedisPool jp = null;
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(MAX_IDLE);
config.setMaxTotal(MAX_ACTIVE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnCreate(true);
config.setTestWhileIdle(true);
config.setTestOnReturn(true);
jp = new JedisPool(config, HOST, PORT, TIMEOUT, PASSWORD, DATABASE);
jedisPool = jp;
threadLocalJedis.set(getJedis());
} catch (Exception e) {
e.printStackTrace();
logger.error("redis服务器异常", e);
}
return jp;
}
/**
* 获取jedis实例
*
* @return jedis
*/
public static Jedis getJedis() {
boolean success = false;
Jedis jedis = null;
int i = 0;
while (!success) {
i++;
try {
if (jedisPool != null) {
jedis = threadLocalJedis.get();
if (jedis == null) {
jedis = jedisPool.getResource();
} else {
if (!jedis.isConnected() && !jedis.getClient().isBroken()) {
threadLocalJedis.set(null);
jedis = jedisPool.getResource();
}
return jedis;
}
} else {
throw new RuntimeException("redis连接池初始化失败");
}
} catch (Exception e) {
logger.error(Thread.currentThread().getName() + "第" + i + "次获取失败");
success = false;
e.printStackTrace();
logger.error("redis服务器异常", e);
}
if (jedis != null) {
success = true;
}
if (i >= 10 && i < 20) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i >= 20 && i < 30) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i >= 30 && i < 40) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i >= 40) {
System.out.println("redis彻底连不上了~~~~(>_<)~~~~");
return null;
}
}
if (threadLocalJedis.get() == null) {
threadLocalJedis.set(jedis);
}
return jedis;
}
/**
* 设置key-value
*
* @param key
* @param value
*/
public static void setValue(byte[] key, byte[] value) {
Jedis jedis = null;
try {
jedis = getJedis();
jedis.set(key, value);
} catch (Exception e) {
threadLocalJedis.set(null);
logger.error("redis服务器异常", e);
throw new RuntimeException("redis服务器异常");
} finally {
if (jedis != null) {
close(jedis);
}
}
}
/**
* 设置key-value,过期时间
*
* @param key
* @param value
* @param seconds
*/
public static void setValue(byte[] key, byte[] value, int seconds) {
Jedis jedis = null;
try {
jedis = getJedis();
jedis.setex(key, seconds, value);
} catch (Exception e) {
threadLocalJedis.set(null);
logger.error("redis服务器异常", e);
throw new RuntimeException("redis服务器异常");
} finally {
if (jedis != null) {
close(jedis);
}
}
}
public static byte[] getValue(byte[] key) {
Jedis jedis = null;
try {
jedis = getJedis();
if (jedis == null || !jedis.exists(key)) {
return null;
}
return jedis.get(key);
} catch (Exception e) {
threadLocalJedis.set(null);
logger.error("redis服务器异常", e);
throw new RuntimeException("redis服务器异常");
} finally {
if (jedis != null) {
close(jedis);
}
}
}
public static long delkey(byte[] key) {
Jedis jedis = null;
try {
jedis = getJedis();
if (jedis == null || !jedis.exists(key)) {
return 0;
}
return jedis.del(key);
} catch (Exception e) {
threadLocalJedis.set(null);
logger.error("redis服务器异常", e);
throw new RuntimeException("redis服务器异常");
} finally {
if (jedis != null) {
close(jedis);
}
}
}
public static void close(Jedis jedis) {
if (threadLocalJedis.get() == null && jedis != null) {
jedis.close();
}
}
public static void clear() {
if (threadLocalJedis.get() == null) {
return;
}
Set<String> keys = threadLocalJedis.get().keys("*");
keys.forEach(key -> delkey(key.getBytes()));
}
}
自定义我们自己的Cache实现类
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.session.mgt.SimpleSession;
import java.io.*;
import java.time.Duration;
import java.util.Collection;
import java.util.Set;
public class MyCache<S, V> implements Cache<Object, Object> {
//设置缓存的过期时间(30分钟)
private Duration cacheExpireTime = Duration.ofMinutes(30);
/**
* 根据对应的key获取值value
*
* @param s
* @return
* @throws CacheException
*/
@Override
public Object get(Object s) throws CacheException {
System.out.println("get()方法....");
byte[] bytes = JedisClient.getValue(objectToBytes(s));
return bytes == null ? null : (SimpleSession) bytesToObject(bytes);
}
/**
* 将K-V保存到redis中
* 注意:保存的value是string类型
*
* @param s
* @param o
* @return
* @throws CacheException
*/
@Override
public Object put(Object s, Object o) throws CacheException {
JedisClient.setValue(objectToBytes(s), objectToBytes(o), (int) cacheExpireTime.getSeconds());
return s;
}
public byte[] objectToBytes(Object object) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] bytes = null;
try {
ObjectOutputStream op = new ObjectOutputStream(outputStream);
op.writeObject(object);
bytes = outputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
public Object bytesToObject(byte[] bytes) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
Object object = null;
try {
ObjectInputStream ois = new ObjectInputStream(inputStream);
object = ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}
/**
* 删除缓存,根据key
*
* @param s
* @return
* @throws CacheException
*/
@Override
public Object remove(Object s) throws CacheException {
return JedisClient.delkey(objectToBytes(s));
}
/**
* 清空所有的缓存
*
* @throws CacheException
*/
@Override
public void clear() throws CacheException {
JedisClient.clear();
}
/**
* 缓存的个数
*
* @return
*/
@Override
public int size() {
return JedisClient.getJedis().dbSize().intValue();
// return redisTemplate.getConnectionFactory().getConnection().dbSize().intValue();
}
@Override
public Set keys() {
return JedisClient.getJedis().keys("*");
}
@Override
public Collection values() {
return null;
}
}
objectToBytes
和bytesToObject
方法是先将session转换成字节数组然后再存到redis中,从redis拿出来也是将字节数组转换成session对象,否则会报错。这是因为shrio使用的是自己包的simpleSession
类,而这个类中的字段都是transient,不能直接序列化,需要我们自己将每个对象转成字节数组才可以进行操作。RedisTemplate
,在配置的时候我们就不用写这两个方法了,直接使用默认的JDK序列化方式即可。private transient Serializable id;
private transient Date startTimestamp;
private transient Date stopTimestamp;
private transient Date lastAccessTime;
private transient long timeout;
private transient boolean expired;
private transient String host;
private transient Map<Object, Object> attributes;
CacheManager
组件,我们还需要在resources文件夹下面新建一个文件夹META-INF
,并在META-INF文件夹下面新建spring.factories
文件。spring.factories
中的内容如下:org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.qzwang.common.cache.config.MyCacheManager
3.4 授权模块common-auth
首先导入我们需要的依赖包
<dependencies>
<dependency>
<groupId>com.qzwang</groupId>
<artifactId>user-dubbo-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--dubbo-->
<dependency>
<groupId>com.gitee.reger</groupId>
<artifactId>spring-boot-starter-dubbo</artifactId>
<version>1.1.3</version>
</dependency>
<!--加入共享会话缓存模块-->
<dependency>
<groupId>com.qzwang</groupId>
<artifactId>common-cache</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
自定义realm,实现对用户访问权限的校验
注意,这里只实现权限校验,不实现用户认证,所以用户认证 doGetAuthenticationInfo
方法直接返回null就行了。
import com.alibaba.dubbo.config.annotation.Reference;
import com.qzwang.user.api.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class UserRealm extends AuthorizingRealm {
@Reference(version = "0.0.1")
private UserService userService;
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户名
String userName = (String) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo authenticationInfo = new SimpleAuthorizationInfo();
System.out.println("username=" + userName);
//给用户设置角色
authenticationInfo.setRoles(userService.selectRolesByUsername(userName));
//给用户设置权限
authenticationInfo.setStringPermissions(userService.selectPermissionByUsername(userName));
return authenticationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
return null;
}
}
shrio的配置中心,shrio的一些核心配置,包括shrio的安全管理器、过滤器都在这个类进行设置。
import com.qzwang.common.cache.config.MyCacheManager;
import com.qzwang.common.cache.config.MySessionDao;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
// ShiroFilterFactoryBean
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 拦截
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
//shiroFilterFactoryBean.setLoginUrl("/user/index");
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
// DefaultWebSecurityManager
// @Qualifier中可以直接是bean的方法名,也可以给bean设置一个name,比如@Bean(name="myRealm"),在@Qulifier中就可以通过name来获取这个bean
@Bean(name = "SecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm,
@Qualifier("myDefaultWebSessionManager") DefaultWebSessionManager defaultWebSessionManager,
@Qualifier("myCacheManager") MyCacheManager myCacheManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联UserRealm
securityManager.setRealm(userRealm);
securityManager.setSessionManager(defaultWebSessionManager);
securityManager.setCacheManager(myCacheManager);
return securityManager;
}
// 创建Realm对象, 需要自定义类
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
/**
* 下面DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor必须定义,
* 否则不能使用@RequiresRoles和@RequiresPermissions
*
* @return
*/
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 设置自定义session管理器
*/
@Bean
public DefaultWebSessionManager myDefaultWebSessionManager(SimpleCookie simpleCookie) {
DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
defaultWebSessionManager.setSessionIdCookie(simpleCookie);
defaultWebSessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());
return defaultWebSessionManager;
}
@Bean
public SimpleCookie simpleCookie() {
SimpleCookie simpleCookie = new SimpleCookie("myCookie");
simpleCookie.setPath("/");
simpleCookie.setMaxAge(30);
return simpleCookie;
}
}
3.5 用户消费者服务user-consumer
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.qzwang</groupId>
<artifactId>user-dubbo-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- dubbo+zookeeper+zkclient -->
<dependency>
<groupId>com.gitee.reger</groupId>
<artifactId>spring-boot-starter-dubbo</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.11</version>
</dependency>
<!--导入缓存管理-->
<dependency>
<groupId>com.qzwang</groupId>
<artifactId>common-cache</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
import com.alibaba.dubbo.config.annotation.Reference;
import com.qzwang.user.api.model.User;
import com.qzwang.user.api.service.UserService;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;
@Component
public class UserRealm extends AuthorizingRealm {
@Reference(version = "0.0.1")
private UserService userService;
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户名
String userName = (String) principalCollection.getPrimaryPrincipal();
System.out.println("userName=" + userName);
SimpleAuthorizationInfo authenticationInfo = new SimpleAuthorizationInfo();
//给用户设置角色
authenticationInfo.setRoles(userService.selectRolesByUsername(userName));
//给用户设置权限
authenticationInfo.setStringPermissions(userService.selectPermissionByUsername(userName));
return authenticationInfo;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String userName = (String) authenticationToken.getPrincipal();
User user = userService.selectByUsername(userName);
if (user != null) {
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), "myRealm");
return authenticationInfo;
}
return null;
}
}
import com.qzwang.common.cache.config.MyCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
// ShiroFilterFactoryBean
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 添加shiro的内置过滤器
/*
anon: 无需认证就能访问
authc: 必须认证了才能访问
UserController: 必须拥有 记住我 功能才能访问
perms: 拥有某个资源权限才能访问
role: 拥有某个角色权限才能访问
*/
// 拦截
Map<String, String> filterMap = new LinkedHashMap<>();
// 授权
// filterMap.put("/UserController/add", "perms[UserController:add]");
filterMap.put("/user/testFunc", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
// 设置未授权页面
shiroFilterFactoryBean.setUnauthorizedUrl("/user/unAuth");
// 设置登录的请求
// shiroFilterFactoryBean.setLoginUrl("/user/index");
return shiroFilterFactoryBean;
}
// DefaultWebSecurityManager
// @Qualifier中可以直接是bean的方法名,也可以给bean设置一个name,比如@Bean(name="myRealm"),在@Qulifier中就可以通过name来获取这个bean
@Bean(name = "SecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm,
@Qualifier("myDefaultWebSessionManager") DefaultWebSessionManager defaultWebSessionManager,
@Qualifier("myCacheManager") MyCacheManager myCacheManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联UserRealm
securityManager.setRealm(userRealm);
securityManager.setCacheManager(myCacheManager);
securityManager.setSessionManager(defaultWebSessionManager);
return securityManager;
}
/**
* 下面DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor必须定义,
* 否则不能使用@RequiresRoles和@RequiresPermissions
*
* @return
*/
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 设置自定义session管理器
*/
@Bean
public DefaultWebSessionManager myDefaultWebSessionManager(SimpleCookie simpleCookie) {
DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
defaultWebSessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());
defaultWebSessionManager.setSessionIdCookie(simpleCookie);
return defaultWebSessionManager;
}
@Bean
public SimpleCookie simpleCookie() {
SimpleCookie simpleCookie = new SimpleCookie("myCookie");
simpleCookie.setPath("/");
simpleCookie.setMaxAge(30);
return simpleCookie;
}
}
import com.qzwang.common.core.config.ExceptionConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Properties;
@Configuration
public class AuthorizationExceptionConfig {
Logger logger = LoggerFactory.getLogger(ExceptionConfig.class);
/**
* 捕获未认证的方法
*
* @return
*/
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("org.apache.shiro.authz.AuthorizationException", "/user/unAuth");
simpleMappingExceptionResolver.setExceptionMappings(properties);
return simpleMappingExceptionResolver;
}
}
@RestController
@RequestMapping("/user")
public class UserController {
@Reference(version = "0.0.1")
private UserService userService;
@RequestMapping(value = "/login", method = RequestMethod.POST)
public R login(@RequestBody User user) {
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
return R.ok();
} catch (Exception e) {
e.printStackTrace();
return R.failed();
}
}
@RequestMapping(value = "/unAuth", method = RequestMethod.GET)
public R unAuth() {
return R.failed("该用户未授权!");
}
@RequiresRoles("admin")
@RequestMapping(value = "/testFunc", method = RequestMethod.GET)
public R testFunc() {
return R.ok("yes success!!!");
}
}
/user/testFunc
接口,注意此接口需要admin角色,但是现在数据库中zhangsan用户并没有该角色,因此也就没有权限访问该接口。3.6 视频消费者服务video-consumer
<dependencies>
<dependency>
<groupId>com.qzwang</groupId>
<artifactId>common-auth</artifactId>
<version>0.0.1</version>
</dependency>
<!-- dubbo+zookeeper+zkclient -->
<dependency>
<groupId>com.gitee.reger</groupId>
<artifactId>spring-boot-starter-dubbo</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.11</version>
</dependency>
</dependencies>
common-auth
模块,在这个模块中配置每个接口需要认证才能访问,我们首先测试一下未登录访问该接口。@RestController
@RequestMapping("/video")
public class VideoController {
@RequestMapping("/getVideo")
public R getVideo() {
return R.ok();
}
}
@RestController
@RequestMapping("/video")
public class VideoController {
@RequestMapping("/getVideo")
@RequiresRoles("admin")
public R getVideo() {
return R.ok();
}
}
/user/unAuth
是在用户服务中,提示找不到该接口,这里需要给这些微服务配置一个网关gateway(这里就不展开怎么配置了,这不是本篇的重点)。上面当用户有admin角色时访问该接口测试如下。END
架构师交流群 「架构君」建立了读者架构师交流群,大家可以添加小编微信进行加群。欢迎有想法、乐于分享的朋友们一起交流学习。
扫描添加好友邀你进架构师群,加我时注明【姓名+公司+职位】
强势开源一款小程序!
2021-11-07
强力推荐一个完善的物流(WMS)管理项目(附代码)
2021-10-23
推荐一个 Spring Boot + MyBatis + Vue 音乐网站
2021-10-19
分享一套家庭理财系统(附源码)
2021-09-20
推荐一个互联网企业级别的开源支付系统
2021-09-04
推荐一套开源通用后台管理系统(附源码)
2021-08-21
一款神仙接私活儿软件,吊到不行!
2021-07-31
基于 SpringBoot 的仿豆瓣平台【源码分享】
2021-07-18
干掉 Wordpress!这个开源建站神器有点吊!
2021-06-18
如有收获,点个在看,诚挚感谢