发表于: 2017-07-11 22:31:47

2 1261


今天完成的事情:springboot整合shiro主体代码完成

创建数据库

这里写图片描述

项目结构

pom

<?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>com.us</groupId>
   <artifactId>shiro</artifactId>
   <version>1.0-SNAPSHOT</version>

   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>1.5.4.RELEASE</version>
       <relativePath></relativePath>
   </parent>

   <properties>
       <start-class>com.unistacks.epp.manager.Application</start-class>
       <maven.compiler.target>1.8</maven.compiler.target>
       <maven.compiler.source>1.8</maven.compiler.source>

       <mybatis.version>3.2.7</mybatis.version>
       <mybatis-spring.version>1.2.2</mybatis-spring.version>
   </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
           <exclusions>
               <exclusion>
                   <groupId>org.springframework.boot</groupId>
                   <artifactId>spring-boot-starter-logging</artifactId>
               </exclusion>
           </exclusions>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-thymeleaf</artifactId>
       </dependency>
       <dependency>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
           <version>1.2</version>
       </dependency>

       <!--shiro相关-->
       <dependency>
           <groupId>org.apache.shiro</groupId>
           <artifactId>shiro-spring</artifactId>
           <version>1.2.5</version>
       </dependency>
       <dependency>
           <groupId>org.apache.shiro</groupId>
           <artifactId>shiro-ehcache</artifactId>
           <version>1.2.5</version>
       </dependency>
       <dependency>
           <groupId>com.github.theborakompanioni</groupId>
           <artifactId>thymeleaf-extras-shiro</artifactId>
           <version>1.2.1</version>
       </dependency>
       <!--log4j12-->

       <dependency>
           <groupId>org.apache.kafka</groupId>
           <artifactId>kafka_2.11</artifactId>
           <version>0.10.1.0</version>
           <exclusions>
               <exclusion>
                   <groupId>org.slf4j</groupId>
                   <artifactId>slf4j-log4j12</artifactId>
               </exclusion>
           </exclusions>
       </dependency>
       <!--db-->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>6.0.5</version>
       </dependency>
       <dependency>
           <groupId>com.mchange</groupId>
           <artifactId>c3p0</artifactId>
           <version>0.9.5.2</version>
           <exclusions>
               <exclusion>
                   <groupId>commons-logging</groupId>
                   <artifactId>commons-logging</artifactId>
               </exclusion>
           </exclusions>
       </dependency>

       <!--mybatis-->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-jdbc</artifactId>
       </dependency>
       <dependency>
           <groupId>org.mybatis</groupId>
           <artifactId>mybatis</artifactId>
           <version>${mybatis.version}</version>
       </dependency>
       <dependency>
           <groupId>org.mybatis</groupId>
           <artifactId>mybatis-spring</artifactId>
           <version>${mybatis-spring.version}</version>
       </dependency>

   </dependencies>
</project>

shiroconfiguration

package com.us.shiro;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;


/**
* shiro配置类
*/
@Configuration
public class ShiroConfiguration {
/**
    * LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
    * 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
    * 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
    */
   @Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
   }

/**
    * HashedCredentialsMatcher,这个类是为了对密码进行编码的,
    * 防止密码在数据库里明码保存,当然在登陆认证的时候,
    * 这个类也负责对form里输入的密码进行编码。
    */
   @Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
       credentialsMatcher.setHashAlgorithmName("MD5");
       credentialsMatcher.setHashIterations(2);
       credentialsMatcher.setStoredCredentialsHexEncoded(true);
       return credentialsMatcher;
   }

/**
    * ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm,
    * 负责用户的认证和权限的处理,可以参考JdbcRealm的实现。
    */
   @Bean(name = "shiroRealm")
@DependsOn("lifecycleBeanPostProcessor")
public ShiroRealm shiroRealm() {
ShiroRealm realm = new ShiroRealm();
//        realm.setCredentialsMatcher(hashedCredentialsMatcher());
       return realm;
   }

//    /**
//     * EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,
//     * 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
//     */
//    @Bean(name = "ehCacheManager")
//    @DependsOn("lifecycleBeanPostProcessor")
//    public EhCacheManager ehCacheManager() {
//        return new EhCacheManager();
//    }

   /**
    * SecurityManager,权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类。
    * //
    */
   @Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
       securityManager.setRealm(shiroRealm());
//        securityManager.setCacheManager(ehCacheManager());
       return securityManager;
   }

/**
    * ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。
    * 它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。
    */
   @Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
       shiroFilterFactoryBean.setSecurityManager(securityManager());

       Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
       LogoutFilter logoutFilter = new LogoutFilter();
       logoutFilter.setRedirectUrl("/login");
//        filters.put("logout",null);
       shiroFilterFactoryBean.setFilters(filters);

       Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();
       filterChainDefinitionManager.put("/logout", "logout");
       filterChainDefinitionManager.put("/user/**", "authc,roles[ROLE_USER]");
       filterChainDefinitionManager.put("/events/**", "authc,roles[ROLE_ADMIN]");
//        filterChainDefinitionManager.put("/user/edit/**", "authc,perms[user:edit]");// 这里为了测试,固定写死的值,也可以从数据库或其他配置中读取
       filterChainDefinitionManager.put("/**", "anon");
       shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);


       shiroFilterFactoryBean.setSuccessUrl("/");
       shiroFilterFactoryBean.setUnauthorizedUrl("/403");
       return shiroFilterFactoryBean;
   }

/**
    * DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
    */
   @Bean
   @ConditionalOnMissingBean
   public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
       defaultAAP.setProxyTargetClass(true);
       return defaultAAP;
   }

/**
    * AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类,
    * 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。
    */
   @Bean
   public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();
       aASA.setSecurityManager(securityManager());
       return aASA;
   }


shirorealm

package com.us.shiro;

import com.us.bean.Permission;
import com.us.bean.Role;
import com.us.bean.User;
import com.us.dao.PermissionDao;
import com.us.dao.UserDao;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class ShiroRealm extends AuthorizingRealm {
private Logger logger = LoggerFactory.getLogger(this.getClass());

   @Autowired
   private UserDao userService;
   @Autowired
   private PermissionDao permissionService;
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.info("doGetAuthorizationInfo+"+principalCollection.toString());
       User user = userService.getByUserName((String) principalCollection.getPrimaryPrincipal());


       //把principals放session中 key=userId value=principals
       SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(user.getId()),SecurityUtils.getSubject().getPrincipals());

       SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
       //赋予角色
       for(Role userRole:user.getRoles()){
info.addRole(userRole.getName());
       }
//赋予权限
       for(Permission permission:permissionService.getByUserId(user.getId())){
//            if(StringUtils.isNotBlank(permission.getPermCode()))
               info.addStringPermission(permission.getName());
       }

//设置登录次数、时间
//        userService.updateUserLogin(user);
       return info;
   }

@Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("doGetAuthenticationInfo +"  + authenticationToken.toString());

       UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
       String userName=token.getUsername();
       logger.info(userName+token.getPassword());

       User user = userService.getByUserName(token.getUsername());
       if (user != null) {
//            byte[] salt = Encodes.decodeHex(user.getSalt());
//            ShiroUser shiroUser=new ShiroUser(user.getId(), user.getLoginName(), user.getName());
           //设置用户session
           Session session = SecurityUtils.getSubject().getSession();
           session.setAttribute("user", user);
           return new SimpleAuthenticationInfo(userName,user.getPassword(),getName());
       } else {
return null;
       }
//        return null;
   }

}

usercontroller

package com.us.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;

import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**
* 登陆控制器
*/
@RestController
public class LoginController {
private Logger logger = LoggerFactory.getLogger(this.getClass());

   @RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(
@RequestParam(value = "username", required = true) String userName,
           @RequestParam(value = "password", required = true) String password,
           @RequestParam(value = "rememberMe", required = true, defaultValue = "false") boolean rememberMe
) {
logger.info("==========" + userName + password + rememberMe);
       Subject subject = SecurityUtils.getSubject();
       UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
       token.setRememberMe(rememberMe);

       try {
subject.login(token);
       } catch (AuthenticationException e) {
e.printStackTrace();
//            rediect.addFlashAttribute("errorText", "您的账号或密码输入错误!");
           return "{\"Msg\":\"您的账号或密码输入错误\",\"state\":\"failed\"}";
       }
return "{\"Msg\":\"登陆成功\",\"state\":\"success\"}";
   }

@RequestMapping("/")
@ResponseBody
   public String index() {
return "no permission";
   }

mybatis相关的dao、mapper就不贴了

明天计划的事情:把jsp页面给弄上来。

遇到的问题:网上的例子很多不全,这个也是照着一个例子写的,然而感觉他这个配置方面没有简化,先学着,一口是吃不下两个胖子的

收获:采用RBAC模式建立数据库

RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。



返回列表 返回列表
评论

    分享到