spring-cloud中使用shiro权限控制

在spring-cloud中使用shiro权限控制,分为网关权限控制和后台逻辑控制。

注意:要在后台做权限认证,必须先在网关做身份认证,将身份认证信息使用redis跨域到后台。本教程的后台权限认证不会运行,要运行还要配置redis。业务比较忙,暂时未写redis这块。

网关权限控制:

一.在网关中主要做用户登录身份认证操作。

1.在pom.xml文件中添加:

<!--  页面拦截时,需要添加的依赖类 ,一下两个类,是访问页面时必须添加的-->

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.4.0</version>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-redis</artifactId>
   <version>1.3.2.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.springframework.session</groupId>
   <artifactId>spring-session-data-redis</artifactId>
</dependency>

<dependency>
   <groupId>org.crazycake</groupId>
   <artifactId>shiro-redis</artifactId>
   <version>2.4.2.1-RELEASE</version>
</dependency>

2.在application.yml中添加

spring:
  profiles:
    active:

    - shiro

3.application-shiro.properties文件中添加如下:

shiro.filter=/css/**,/js/**,/favicon.ico
shiro.logout=/logout
shiro.authc=/**
shiro.loginUrl=/login
shiro.sucessUrl=/index

shiro.errorUrl=/403

4.配置文件ShiroConfig和MyShiroRealm

ShiroConfig内容如下:

@Configuration
public class ShiroConfig {
/** 不需要过滤的文件地址,以逗号(,)分隔 ***/
@Value("${shiro.filter}")
private String strFilter;
/** 配置退出 过滤器 **/
@Value("${shiro.logout}")
private String strLogout;
/** authc:所有url都必须认证通过才可以访问 **/
@Value("${shiro.authc}")
private String strAuthc;
/** 登录地址 **/
@Value("${shiro.loginUrl}")
private String strLoginUrl;
/** 成功后跳转地址 **/
@Value("${shiro.sucessUrl}")
private String strSuccessUrl;
/** 错误地址 **/
@Value("${shiro.errorUrl}")
private String strErrorUrl;

/**
* ShiroFilterFactoryBean 处理拦截资源文件问题。
* 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
* 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
*
* Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
* 3、部分过滤器可指定参数,如perms,roles
*
*/
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置不会被拦截的链接 顺序判断
String[] arrayFilter = strFilter.split(",");
Map<String, String> map = new HashMap<String, String>();
for (String str : arrayFilter) {
map.put(str, "anon");
}
filterChainDefinitionMap.put("/gate-ui/static/**", "anon");
filterChainDefinitionMap.putAll(map);
// 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put(strLogout, "logout");
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put(strAuthc, "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl(strLoginUrl);
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl(strSuccessUrl);

// 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl(strErrorUrl);
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}


/**
* 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 )

* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);// 散列的次数,比如散列两次,相当于md5(md5(""));
return hashedCredentialsMatcher;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
// 设置md5加密
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
/**
* cookie对象;
* @return
*/
@Bean
public SimpleCookie rememberMeCookie(){
  //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
  SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
  //<!-- 记住我cookie生效时间30天 ,单位秒;-->
  simpleCookie.setMaxAge(3800);
  return simpleCookie;
}


/**
* cookie管理对象;记住我功能
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager(){
  CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
  cookieRememberMeManager.setCookie(rememberMeCookie());
  //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
  //cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
  return cookieRememberMeManager;
}

@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(myShiroRealm());
   //注入记住我管理器;
   securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}

/**
* 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;

* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}

@Bean(name = "simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");// 数据库异常处理
mappings.setProperty("UnauthorizedException", "403");
r.setExceptionMappings(mappings); // None by default
r.setDefaultErrorView("error"); // No default
r.setExceptionAttribute("ex"); // Default is "exception"
// r.setWarnLogCategory("example.MvcLogger"); // No default
return r;
}

MyShiroRealm内容如下:

public class MyShiroRealm extends AuthorizingRealm {
@Autowired
    private SecurityShiroService securityShiroService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    return null;
    }
    /*主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        //获取用户的输入的账号.
        String name = (String)token.getPrincipal();
        
        //通过name从数据库中查找 User对象,如果找到,没找到.
        //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        Map<String, Object> map= new HashMap<String, Object>();
        map.put("uName", name);      
        User user = securityShiroService.selectByUserInfo(map);
        if(user == null){
            return null;
        }     
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user, //用户名
                user.getuPass(), //密码
                ByteSource.Util.bytes(user.getuName()+"haohao"),//salt=username+salt
                getName()  //realm name
        );
        
        // 当验证都通过后,把用户信息放在session里
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute("userInfo", user);
        return authenticationInfo;

二.在后台逻辑控制中主要做操作权限控制,分为角色和方法的操作权限,目前主要做方法的操作权限。

1.在pom.xml文件中添加:

<!--  页面拦截时,需要添加的依赖类 ,一下两个类,是访问页面时必须添加的-->        

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.4.0</version>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-redis</artifactId>
   <version>1.3.2.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.springframework.session</groupId>
   <artifactId>spring-session-data-redis</artifactId>
</dependency>

<dependency>
   <groupId>org.crazycake</groupId>
   <artifactId>shiro-redis</artifactId>
   <version>2.4.2.1-RELEASE</version>
</dependency>

2.在application.yml中添加

spring:
  profiles:
    active:

    - shiro

3.application-shiro.properties文件中添加如下:

shiro.filter=/**
shiro.logout=/logout
shiro.authc=/test
shiro.loginUrl=/login
shiro.sucessUrl=/gate-ui/index
shiro.errorUrl=/403

4.配置文件ShiroConfig和MyShiroRealm

ShiroConfig内容如下:

@Configuration
public class ShiroConfig {
/** 不需要过滤的文件地址,以逗号(,)分隔 ***/
@Value("${shiro.filter}")
private String strFilter;
/** 配置退出 过滤器 **/
@Value("${shiro.logout}")
private String strLogout;
/** authc:所有url都必须认证通过才可以访问 **/
@Value("${shiro.authc}")
private String strAuthc;
/** 登录地址 **/
@Value("${shiro.loginUrl}")
private String strLoginUrl;
/** 成功后跳转地址 **/
@Value("${shiro.sucessUrl}")
private String strSuccessUrl;
/** 错误地址 **/
@Value("${shiro.errorUrl}")
private String strErrorUrl;

/**
 * ShiroFilterFactoryBean 处理拦截资源文件问题。
 * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
 * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
 *
 * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
 * 3、部分过滤器可指定参数,如perms,roles
 *
 */
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置不会被拦截的链接 顺序判断
String[] arrayFilter = strFilter.split(",");
Map<String, String> map = new HashMap<String, String>();
for (String str : arrayFilter) {
map.put(str, "anon");
}
filterChainDefinitionMap.putAll(map);
// 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put(strLogout, "logout");
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put(strAuthc, "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl(strLoginUrl);
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl(strSuccessUrl);

// 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl(strErrorUrl);
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}


/**
 * 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 )
 * 
 * @return
 */
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);// 散列的次数,比如散列两次,相当于md5(md5(""));
return hashedCredentialsMatcher;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
// 设置md5加密
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
/**
 * cookie对象;
 * @return
 */
@Bean
public SimpleCookie rememberMeCookie(){
   //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
   SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
   //<!-- 记住我cookie生效时间30天 ,单位秒;-->
   simpleCookie.setMaxAge(3800);
   return simpleCookie;
}


/**
 * cookie管理对象;记住我功能
 * @return
 */
@Bean
public CookieRememberMeManager rememberMeManager(){
   CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
   cookieRememberMeManager.setCookie(rememberMeCookie());
   //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
   //cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
   return cookieRememberMeManager;
}

@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(myShiroRealm());
    //注入记住我管理器;
    securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}

/**
 * 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;
 * 
 * @param securityManager
 * @return
 */
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}

@Bean(name = "simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");// 数据库异常处理
mappings.setProperty("UnauthorizedException", "403");
r.setExceptionMappings(mappings); // None by default
r.setDefaultErrorView("error"); // No default
r.setExceptionAttribute("ex"); // Default is "exception"
// r.setWarnLogCategory("example.MvcLogger"); // No default
return r;
}

MyShiroRealm内容如下:

public class MyShiroRealm extends AuthorizingRealm {
@Autowired
    private SecurityShiroService securityShiroService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
      SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user  = (User)principals.getPrimaryPrincipal();
        /*添加加上角色名称和角色下面所有拥有的所有权限值*/
        authorizationInfo.addRole(user.gettRoleName());
        List<Permission> permissions = user.getPermissions();
        if(permissions != null && permissions.size()>0){
        for(int i=0; i<permissions.size();i++){
        authorizationInfo.addStringPermission(permissions.get(i).gettPermission());
        }
        }
        return authorizationInfo;
    }
    /*主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {

       return null;

}

猜你喜欢

转载自blog.csdn.net/kunzai6/article/details/79484479