SpringBoot整合Shiro

SpringBoot整合Shiro

SpringBoot整合Shiro流程

  1. 引入shiro-spring依赖
  2. 编写自定义的Realm它需要继承于AuthorizingRealm。
  3. 编写ShiroConfig
  4. 使用Shiro

引入shiro-spring依赖

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

编写自定义Realm

public class UserRealm extends AuthorizingRealm {
    /**
     *为用户添加角色与权限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = (String) ((User) principalCollection.getPrimaryPrincipal()).getName();
        //添加用户角色
        Set<String> roleSets = new HashSet<String>();
        roleSets.add("user1");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(roleSets);

        //添加用户权限
        Set<String> permissions = new HashSet<String>();
        permissions.add("select");
        permissions.add("list");
        permissions.add("add");
        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }

    /**
     * 对用户进行登入验证,用户登入时会将站号密码通过Subject的login方法传入过来
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = UserService.map.get(token.getUsername());
        if (user == null) {
            return null;
        }
        if (!user.getPassword().equals("用户密码")) {
            return null;
        }
        return new SimpleAuthenticationInfo(user, user.getPassword(), "");
    }
}

编写ShiroConfig

@Configuration
public class ShiroConfig {

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;
    }

    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        filterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置那些资源路径需要访问权限那些不需要
        Map<String, String> filterMap = new HashMap<String, String>();
        filterMap.put("/user", "authc");
        //这里需要对login页面进行放行让用户可以直接访问这个页面
        filterMap.put("/login", "anon");
        filterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return filterFactoryBean;
    }

    @Bean(name = "userRealm")
    public UserRealm getUserRealm(){
        return new UserRealm();
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解
     * 的类,并在必要时进行安全逻辑验证
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

}

使用Shiro

编写登入页面,并对用户进行登入验证:

@RestController
public class UserLogin {

    @GetMapping("/login")
    public String login(@RequestParam("username") String name, @RequestParam("password") String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(name, password);
        Subject subject = SecurityUtils.getSubject();
        try{
            //将账号密码传到UserRealm中对其进行验证
            subject.login(token);
        }catch (Exception e){
            e.printStackTrace();
            return "login fail";
        }
        return "login success";
    }
}

使用注解对用户进行权限验证,这需要用户先登入:

@RestController
public class UserController {

    @RequiresPermissions("list:add")
    @GetMapping("/test")
    public String test(){
        return "you have permission!";
    }

}

更进一步

当用户访问一个页面时,如果用户没有权限那么用户将会跳转到Shiro定义的toLogin页面,如果是一个前后端分离的项目这样显然是不可取的,通过下面的方法可以让用户得到认证失败的信息而不是跳转页面。

  1. 编写自定义Filter:这个Filter需要继承于FormAuthenticationFilter并覆写onAccessDenied方法。
  2. 将这个Filter添加到ShiroConfig配置类的getShiroFilterFactoryBean方法里
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setStatus(200);
        httpServletResponse.setContentType("application/json;charset=utf-8");

        PrintWriter out = httpServletResponse.getWriter();
        out.println("认证失败请重新登入!");
        out.flush();
        out.close();
        return false;
    }
}
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        filterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置那些资源路径需要访问权限那些不需要
        Map<String, String> filterMap = new HashMap<String, String>();
        filterMap.put("/user", "authc");
        filterMap.put("/login", "anon");
        filterFactoryBean.setFilterChainDefinitionMap(filterMap);
        Map<String, Filter> map = new HashMap<String, Filter>();
        map.put("authc", new MyFormAuthenticationFilter());
        filterFactoryBean.setFilters(map);
        return filterFactoryBean;
    }

这样只要是需要权限authc的用户认证失败将不会跳转页面,而是返回失败信息。

posted @ 2021-04-18 16:45  TKG  阅读(65)  评论(0)    收藏  举报