springBoot集成shiro(前后台分离)

一、pom文件所需

<!--shiro-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>net.sourceforge.nekohtml</groupId>
    <artifactId>nekohtml</artifactId>
    <version>1.9.22</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.2.2</version>
</dependency>

二、Shiro配置类

package com.*.config.shiro;

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.mgt.SecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        //创建一个shiro过滤器工厂
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
        shiroFilterFactoryBean.setLoginUrl("/notLogin");
        // 设置无权限时跳转的 url;
        shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");
        // 设置拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //开放登陆接口
        filterChainDefinitionMap.put("/login", "anon");
        //其余接口一律拦截
        //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        System.out.println("Shiro拦截器工厂类注入成功");
        return shiroFilterFactoryBean;
    }

    /**
     * 注入 securityManager
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(customRealm());
        return securityManager;
    }

    /**
     * 自定义身份认证 realm;
     * 必须写这个类,并加上 @Bean 注解,目的是注入 CustomRealm,
     * 否则会影响 CustomRealm类 中其他类的依赖注入
     * @return
     */
    @Bean
    public CustomRealm customRealm() {
        return new CustomRealm();
    }

    //为当前shiro配置aop切面 使shiro与springAOP结合
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


}

三、身份认证及权限认证

package com.*.config.shiro;

import com.*.sys.user.mapper.UserMapper;
import com.*.sys.user.pojo.User;
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.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

public class CustomRealm extends AuthorizingRealm {

    private UserMapper userMapper;

    @Autowired
    private void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /**
     * 获取授权信息
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //System.out.println("————权限认证————");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //如果身份认证的时候没有传入User对象,这里只能取到userName
        //也就是SimpleAuthenticationInfo构造的时候第一个参数传递需要User对象
        User user  = (User)principalCollection.getPrimaryPrincipal();
        //获取用户所拥有的所有权限地址
        List<String> reghtList = userMapper.getUserPowerUrlList(user.getId());
        //设置权限集合
        info.addStringPermissions(reghtList);
        return info;
    }

    /**
     * 获取身份验证信息
     * Shiro中,最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
     * @param authenticationToken 用户身份信息 token
     * @return 返回封装了用户信息的 AuthenticationInfo 实例
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //System.out.println("————身份认证方法————");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 根据用户名获取用户信息
        User user = userMapper.queryUserByUserName(token.getUsername());
        if (null != user && user.getStatus() == 1){
            throw new AccountException("此用户已停用!");
        }else if (null == user) {
            throw new AccountException("用户名不正确!");
        }else if (!user.getPassword().equals(new String((char[]) token.getCredentials()))) {
            throw new AccountException("密码不正确!");
        }
        return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    }
}

四、异常捕捉类

@RestControllerAdvice
public class ExceptionController {

    //捕捉 CustomRealm 抛出的异常
    @ExceptionHandler(AccountException.class)
    public ExtObject handleShiroException(Exception ex) {
        return ExtObject.markLoginError(ex.getMessage());
    }

    //捕捉@RequiresPermissions注解,无权限时抛出的异常
    @ExceptionHandler(UnauthorizedException.class)
    public ExtObject handleShiroException1(Exception ex) {
        return ExtObject.notRole("没有此权限!");
    }

}

五、LoginController

@RestController
public class LoginController {

    @GetMapping("notLogin")
    public ExtObject notLogin() {
        return ExtObject.markLoginError("您尚未登陆!");
    }

    @GetMapping("notRole")
    public ExtObject notRole() {
        return ExtObject.notRole("没有此权限!");
    }

    @GetMapping("index")
    public ExtObject index(){
        return ExtObject.markSuccessButNoData("登录成功!");
    }

    @GetMapping("logout")
    public ExtObject logout() {
        Subject subject = SecurityUtils.getSubject();
        //注销
        subject.logout();
        return ExtObject.markSuccessButNoData("成功注销!");
    }

    @PostMapping("login")
    public ExtObject login(@RequestParam String username, @RequestParam String password){
        // 从SecurityUtils里边创建一个 subject
        Subject subject = SecurityUtils.getSubject();
        // 在认证提交前准备 token(令牌)
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        // 执行认证登陆
        subject.login(token);
        //根据权限,指定返回数据
        return ExtObject.markSuccessButNoData("登录成功!");
    }



}

六、测试权限拦截

/**
 * @RequiresPermissions注解中的url就是此方法的接口路径,
 * 对应权限表中的url路径,角色没有此权限就会抛出异常,
 * 在异常捕捉类中,进行捕捉异常并返回无权限提示
 * 如角色用权限,正常访问此接口
 * 如接口上不加此注解,则只要登录成功就可访问
 * 测试权限
 * @return
 */
@RequiresPermissions("/test1")
@GetMapping("test1")
public ExtObject test1(){
    return ExtObject.markSuccess("admin用户有此接口权限",null);
}
@RequiresPermissions("/test2")
@GetMapping("test2")
public ExtObject test2(){
    return ExtObject.markSuccess("admin用户无此接口权限",null);
}
@GetMapping("test3")
public ExtObject test3(){
    return ExtObject.markSuccess("登录后可以任意访问此接口",null);
}

 

/**
 * 测试结果:
 *
 *  首先登录admin用户,登录成功。
 *
 *  访问 /test1 接口,正常返回接口数据
 *
 *  访问 /test2 接口,返回无权限提示信息
 *
 *  访问 /test3 接口,正常返回接口数据
 *
 */

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值