zoukankan      html  css  js  c++  java
  • springboot集成shiro 实现权限控制(转)

    shiro

    apache shiro 是一个轻量级的身份验证与授权框架,与spring security 相比较,简单易用,灵活性高,springboot本身是提供了对security的支持,毕竟是自家的东西。springboot暂时没有集成shiro,这得自己配。

    shiro 内置过滤器

    请看博文:
    http://blog.csdn.net/hxpjava1/article/details/7035724

    本文实现:

    本文实现从数据库读取用户信息,获取当前用户的权限或角色,通过配置文件过滤用户的角色或权限。拥有相应的角色或者相应的权限的用户可以访问相应的url。

    数据库设计

    这里写图片描述

    1. 添加依赖

      <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>

    2. 添加shiro 配置



    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配置类
    * Created by cdyoue on 2016/10/21.
    */

    @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<>();
    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]");//用户为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;
    } }

    3. 添加Realm 验证

    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;

    /**
    * Created by cdyoue on 2016/10/21.
    */

    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;
    }
    }

    4. 添加controller

    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;


    /**
    * Created by cdyoue on 2016/10/21.
    * 登陆控制器
    */

    @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";
    }
    }

    此处代码不全,只是写了springboot 整合的主要类,如果需要全部代码请移步。。。

    源码:https://github.com/527515025/springBoot

  • 相关阅读:
    【BZOJ1046】[HAOI2007]上升序列
    【BZOJ1045】[HAOI2008]糖果传递
    【BZOJ1044】[HAOI2008]木棍分割
    【BZOJ1041】[HAOI2008]圆上的整点
    【LG2257】YY的GCD
    【BZOJ1018】[SHOI2008]堵塞的交通
    【LG4735】最大异或和
    【POJ2182】Lost Cows
    【POJ2482】Stars in Your Window
    【POJ1733】Parity game
  • 原文地址:https://www.cnblogs.com/jpfss/p/8308806.html
Copyright © 2011-2022 走看看