spingboot+shiro实现后端权限管理

⭐shiro的结构图

⭐shiro内部采用的是session+sessionId进行的会话管理(有状态认证)

⭐当然你也可以整合jwt实现无状态认证

Ok,直接干货!!!!

1. 第一步:加依赖

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

2.第二步:写一个shiroConfig类

@Configuration
public class ShiroConfig {
    /**
     * 创建shiro的一个过滤器
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
        /**
         * 添加shiro的内置过滤器:一般用两种 anon:允许通过;authc:必须认证
         * 还有就是user:如果使用rememberMe的功能就可以访问
         * perms:该资源必须得到权限资源才可以访问
         * role:必须得到角色权限才可以访问
         */
        //必须保证顺序插入所以使用LinkedHashMap
        Map<String, String> filterMap = new LinkedHashMap<>();
        //认证过滤器
        filterMap.put("自定义无需认证", "anon");
        //filterMap.put("/user/*", "authc");
        //授权过滤器
        filterMap.put("/user/hello", "perms[自定义]");//例子:user:add
        //未认证的跳转页面(也就是未登录的用户)
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        //未授权访问跳转的页面(也就是没有权限的用户)
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 创建SecurityManager
     */
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联Realm
        securityManager.setRealm(getRealm());
        return securityManager;
    }

    /**
     * 创建Realm:需要自定义一个realm的类
     */
    @Bean
    public MyRealm getRealm() {
        MyRealm myRealm = new MyRealm();
        // 配置 加密 (在加密后,不配置的话会导致登陆密码失败)
        myRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myRealm;
    }

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 使用md5 算法进行加密
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        // 设置散列次数: 意为加密几次
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }
}

3.第三步:写一个自定义的认证授权Realm

public class MyRealm extends AuthorizingRealm {
    /**
     * 执行授权逻辑
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取登录用户信息
        Object primaryPrincipal = principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //执行授权逻辑
        info.addStringPermission("user:add");
        return info;
    }

    /**
     * 执行认证逻辑
     *
     * @param authenticationToken:这个就是前面subject.login()传递过来的token
     * @return 认证不通过就返回null
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //执行认证的过程
        //从数据库拿出账号密码和用户传递过来的账号密码对比
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        String username = usernamePasswordToken.getUsername();
        //数据查询账号密码
        if (!username.equals("数据库账号")) {
            return null;//返回为空,shiro会抛出UnKnowAccountException(也就是账号不存在)
        }
        //密码不需要判断,直接返回一个AuthenticationInfo的实现类,把数据库密码做参数,shiro会自己判断的
        //shiro内置的加密算法
        ByteSource credentialsSalt = ByteSource.Util.bytes("user.getUsername" + "user.getSalt()");//从数据库查询的
        return new SimpleAuthenticationInfo(username, "数据库加密之后的密码", credentialsSalt, this.getName());
    }
}

4.第四步:写一个登录方法吧

@RequestMapping("/user")
public class UserController {
    /**
     * 使用shiro进行登录认证操作
     */
    @GetMapping(value = "/login")
    public String login(String name, String password) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(name, password);
        //传入一个AuthenticationToken类型的token,这里貌似UsernamePasswordToken类型的token会自动转化为AuthenticationToken
        subject.login(token);
        //login会直接交给shiro的自定义的Realm的认证方法处理
        //登录失败的话就会抛出异常,根据异常类别来判断错误的类型,比如说:账号不存在或者密码错误:抛异常可以用try catch来抛出不同异常,但是我们也可以自定义统一异常处理类,这里就不详述了,可以看我另一个博客
        /**
         *
         */
        return "登录成功";
    }

    @GetMapping("/hello")
    public void run() {
        System.out.println("hello");
    }
}

⭐ok,这样就结束了,shiro的Security Manager会帮你管理这一切的

posted @ 2020-09-11 12:01  未名丶花开丶  阅读(229)  评论(0)    收藏  举报