SpringBoot(二)整合安全框架Shiro

基于:【狂神说Java】SpringBoot最新教程IDEA版通俗易懂

1 Shiro架构

Shiro三个核心组件:Subject, SecurityManager 和 Realms.

  • Subject:主体,可以看到主体可以是任何可以与应用交互的 “用户”;
  • SecurityManager:相当于 SpringMVC 中的 DispatcherServlet 或者 Struts2 中的 FilterDispatcher;是 Shiro 的心脏;所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理。
  • Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

2 使用SpringBoot整合Shiro

2.1 导入依赖

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

2.2 编写配置文件ShiroConfig

@Configuration
public class ShiroConfig {

    //创建reaml对象,需要自定义
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

    //SecurityManager
    @Bean
    public DefaultWebSecurityManager SecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm,因为是他的管理者
        securityManager.setRealm(userRealm);

        return securityManager;
    }

    //ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        // 设置SecurityManager
        factoryBean.setSecurityManager(securityManager);

        // 添加过滤器
        LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();

        /*
            anon:不需要登录就能访问,一般用于静态资源,或者移动端接口
            authc:需要登录认证才能访问的资源
            perms:验证用户是否拥有资源权限
            roles:验证用户是否拥有资源角色
            user:用户已经身份验证 / 记住我登录的都可
        */

        // 直接访问
        filterMap.put("/","anon");
        filterMap.put("/index","anon");
        filterMap.put("/user/login","anon");

        //登录了的才能查看自己和注销
        filterMap.put("/user/me","authc");
        filterMap.put("/user/layout","authc");

        // 登录了都能访问鸢尾花
        filterMap.put("/iris","authc");
//        filterMap.put("/pm25","authc");

        // 授权canVisitPM25的用户才能访问pm链接
        filterMap.put("/pm25","perms[canVisitPM25]");

        // 把map放进去
        factoryBean.setFilterChainDefinitionMap(filterMap);

        // 设置登录失败的跳转权限
        factoryBean.setLoginUrl("/pleaseLogin");

        // 权限不足跳的链接
        factoryBean.setUnauthorizedUrl("/insufficientAuthority");

        return factoryBean;
    }

}

这是Shiro的核心配置文件,依次有三个核心对象,UserRealmDefaultWebSecurityManagerShiroFilterFactoryBean基本是固定写法,需要根据业务来配置的就是过滤器的规则,即哪些页面需要哪些权限才能访问。

2.2 编写自定义的Realm

public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserServiceImpl userService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行shiro授权");

        // 权限
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("canVisitPM25");

        // 参数principalCollection就是登录成功后,user对象信息,可以根据数据库情况决定是否授权

        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行shiro认证");

        // 把传入参数的token转为UsernamePasswordToken
        UsernamePasswordToken userToken=(UsernamePasswordToken)authenticationToken;

        // 数据库取信息
        User user = userService.getUserByUname(userToken.getUsername());

        if(user==null) return null;//没有这个用户

        // 判断密码
        return new SimpleAuthenticationInfo(user,user.getUpassword(),"");
    }
}

配置文件定义了完整的访问权限和规则,那么Relm就是具体的授权和认证功能,二者都需要去数据库查询;

2.3 ShiroService服务类

@Service
public class ShiroServiceImpl implements ShiroService {

    @Override
    public String login(String username, String pwd) {
        // 获得当前访问的用户
        Subject subject = SecurityUtils.getSubject();
        // 封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, DigestUtils.md5DigestAsHex(pwd.getBytes()));
        // 开始验证
        try {
            subject.login(token);
            return "登录成功";
        }catch (UnknownAccountException e){//用户名不存在
            return "用户名不存在";
        }catch (IncorrectCredentialsException e){//密码错误
            return "密码错误";
        }
    }

    @Override
    public String showMe() {
        return SecurityUtils.getSubject().toString();
    }

    @Override
    public String logout() {
        SecurityUtils.getSubject().logout();
        return "注销成功";
    }
}

SecurityUtils.getSubject()可以获得当前的用户,然后对其进行相应的权限控制。

3 原理

  • SpringBoot对于Shiro的封装较深,逻辑层面不是很好理解,直接使用官网的非web项目例子比较好理解;
  • 如何判断当前访问的用户就是已经登录过的,还需要了解ThreadLocal相关的知识;
  • 如何绑定浏览器访问者和subject用户,需要靠cookie来保证,这部分知识可以通过实践的出来;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值