SpringBoot集成Shiro安全框架

使用技术:

  • SpringBoot 2.0

  • Shiro

  • MyBatis-Plus

项目地址:https://github.com/jitwxs/blog_sample

1.导入依赖

<!-- SpringBoot Web包 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>

<!-- SpringBoot AOP包,用于Shiro授权 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!--Shiro核心包 -->
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>1.2.5</version>
</dependency>

<!--MyBatis-Plus和SpringBoot整合包 -->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatisplus-spring-boot-starter</artifactId>
	<version>1.0.5</version>
</dependency>
	
<!--MyBatis-Plus核心包 -->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus</artifactId>
	<version>2.1.9</version>
</dependency>

<!-- 数据库连接包 -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>

2.自定义ShiroRealm

继承AuthorizingRealm 类,并重写用于认证的doGetAuthenticationInfo和用于授权的doGetAuthorizationInfo,如果你在SSM中使用过Shiro,就很简单了。

/**
 *
 * @author jitwxs
 * @date 2018/3/20 9:35
 */

public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    IUserService userService;

    @Autowired
    IUserRoleService userRoleService;

    @Autowired
    IRoleService roleService;

    @Autowired
    IPermissionService permissionService;

    @Autowired
    IRolePermissionService rolePermissionService;

    /**
     * 用户认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        if(token.getPrincipal() == null) {
            return null;
        }

        // 获取用户名和密码
        String name = token.getPrincipal().toString();
        String password = new String((char[])token.getCredentials());

        User user = userService.findByName(name);

        if(user  == null || !password.equals(user.getPassword())) {
            throw new IncorrectCredentialsException("登录失败,用户名或密码错误");
        }

        //验证authenticationToken和simpleAuthenticationInfo的信息
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name,password, getName());

        // 返回一个身份信息
        return simpleAuthenticationInfo;
    }

    /**
     * 角色权限和对应权限添加
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取用户名
        String name = (String)principalCollection.getPrimaryPrincipal();
        // 获取用户对象
        User user = userService.findByName(name);
        // 添加角色和权限

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        List<Role> roles = getRoles(user.getId());

        for(Role role : roles) {
            // 添加角色
            simpleAuthorizationInfo.addRole(role.getName());

            // 添加权限
            List<Permission> permissions = getPermission(role.getId());
            for(Permission permission : permissions) {
                simpleAuthorizationInfo.addStringPermission(permission.getName());
            }
        }
        return simpleAuthorizationInfo;
    }


    private List<Role> getRoles(String userId) {
        List<UserRole> userRoles = userRoleService.selectList(
                new EntityWrapper<UserRole>()
                    .eq("user_id", userId));
        List<Role> list = new ArrayList<>();

        for(UserRole userRole : userRoles) {
            Role role = roleService.selectById(userRole.getRoleId());
            list.add(role);
        }
        return list;
    }

    private List<Permission> getPermission(String roleId) {
        List<RolePermission> rolePermissions = rolePermissionService.selectList(
                new EntityWrapper<RolePermission>()
                    .eq("role_id", roleId));

        List<Permission> list = new ArrayList<>();

        for(RolePermission rolePermission : rolePermissions) {
            Permission permission = permissionService.selectById(rolePermission.getPermissionId());
            list.add(permission);
        }
        return list;
    }
}

3.设置ShiroConfig

SpringBoot相较于SSM,将配置使用注解形式引入,那么原本写入xml的Shrio配置文件,就可以用注解注入了:

/**
 * @author jitwxs
 * @date 2018/3/20 10:00
 */
@Configuration
public class ShiroConfig {
    /**
     * 注入ShiroRealm
     * 不能省略,会导致ShiroRealm中service无法注入
     */
    @Bean
    public ShiroRealm shiroRealm() {
        return new ShiroRealm();
    }

    /**
     * 注入securityManager
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(shiroRealm());
        return manager;
    }

    /**
     * Filter工厂,设置过滤条件
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

        // Shiro的核心安全接口
        bean.setSecurityManager(securityManager);

        // 设置登陆页
        bean.setLoginUrl("/login");

        // 自定义拦截规则
        Map<String,String> map = new HashMap<>(16);
        map.put("/", "anon");
        // 设置登出
        map.put("/logout", "logout");
        // 对所有用户认证
        map.put("/**", "authc");

        bean.setFilterChainDefinitionMap(map);
        return bean;
    }

    /**
     * 注册AuthorizationAttributeSourceAdvisor
     * 如果要开启注解@RequiresRoles等注解,必须添加
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager manager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(manager);

        return advisor;
    }
}

4.编写Controller测试

这里只是简单的编写了一些测试方法:

@Controller
public class LoginController {
    @Autowired
    IUserService userService;

    @GetMapping("/")
    public String index() {
        return "index.html";
    }

    @GetMapping("/login")
    public String login() {
        return "login.html";
    }

    @PostMapping("/login")
    public String login(User user) {

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
                user.getName(), user.getPassword());
        //进行验证,这里可以捕获异常,然后返回对应信息
        subject.login(usernamePasswordToken);

        return "redirect:/home";
    }

    @GetMapping("/home")
    public String home() {
        return "home.html";
    }

    @RequestMapping("/logout")
    public String logout() {
        return "redirect:/logout";
    }

    @RequiresRoles("admin")
    @RequiresPermissions("create")
    @RequestMapping("/adminCreate")
    @ResponseBody
    public String adminCreate() {
        return "只有[admin]身份且具有[create]权限才能看见这句话";
    }
}

5.测试程序

我的数据库拥有以下身份和权限:

RolePermissions
admincreate、update、delete、select
teachercreate、select
studentselect

拥有以下几位用户:

UserRole
jitwxsadmin
zhangsanstudent

当我测试该方法时:

@RequiresRoles("admin")
@RequiresPermissions("update")
@RequestMapping("/adminCreate")
@ResponseBody
public String adminCreate() {
    return "只有[admin]身份且具有[create]权限才能看见这句话";
}

番外:帮你躲坑

在这个例子中,踩了几个坑,罗列一下:

(1)ShiroRealm中无法注入Service

解决办法:Shiro解决无法注入Service问题(包括Spring MVC和Spring Boot)

(2)ShiroRealm的授权方法doGetAuthorizationInfo()没有调用

解决办法:缺少AOP,导入AOP包

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值