springboot 2.1 实践教程(十九)-整合Shiro

Shiro介绍

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

SpringBoot具体整合Shiro的方法如下

1.导入shiro坐标

<!-- Shiro使用Srping框架 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.2</version>
</dependency>

2.创建ShiroConfig,配置Shiro相关的配置

package com.example.systema.shiro;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    /**
     * 1.创建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        bean.setLoginUrl("/toLogin");  //设置未登录拦截后的跳转页面,如果不设置该参数,默认跳转到login.jsp
        bean.setUnauthorizedUrl("/unAuth"); // 权限认证失败,则跳转到指定页面
        // Shiro连接约束配置,即过滤链的定义
        Map<String, String> filterMap = new HashMap<>();
        filterMap.put("/user/login", "anon");//登录操作放行,不需要认证
        filterMap.put("/product/toAdd", "perms[product:add]");  //基于资源的授权过滤器
        filterMap.put("/index","user");  //记住我的过滤器
        filterMap.put("/**", "authc"); //认证过滤器
        bean.setFilterChainDefinitionMap(filterMap);  //设置Shiro过滤器

        //自定义拦截器

        return bean;
    }


    /**
     * 2.创建SecurityManager,并关联Realm
     */
    @Bean
    public SecurityManager securityManager(UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(userRealm);
        // 记住我
        securityManager.setRememberMeManager(rememberMeManager());

        return securityManager;
    }

    /**
     * 3.创建Realm
     */
    @Bean
    public UserRealm myReal() {
        UserRealm myRealm = new UserRealm();
        return myRealm;
    }


    /**
     * 开启Shiro注解通知器
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
            @Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


    /**
     * 记住我
     */
    public CookieRememberMeManager rememberMeManager()
    {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }

    /**
     * cookie 属性设置
     */
    public SimpleCookie rememberMeCookie()
    {
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(120);
        return cookie;
    }
}

3.创建自定义Realm类

package com.example.systema.shiro;

import com.example.systema.domain.User;
import com.example.systema.service.MenuService;
import com.example.systema.service.RoleService;
import com.example.systema.service.UserService;
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.HashSet;
import java.util.Set;

public class UserRealm extends AuthorizingRealm {

    @Autowired
    private MenuService menuService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private UserService userService;

    /**
     * 授权操作
     **/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //授权逻辑操作
        Object obj = SecurityUtils.getSubject().getPrincipal(); //获取用户信息
        User user = (User) obj;
        Set<String> roles = new HashSet<String>();  //角色列表
        Set<String> menus = new HashSet<String>();  //资源列表
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        roles = roleService.selectRoleKeys(user.getUserId());
        menus = menuService.selectPermsByUserId(user.getUserId());
        // 角色加入AuthorizationInfo认证对象
        info.setRoles(roles);
        // 权限加入AuthorizationInfo认证对象
        info.setStringPermissions(menus);
        return info;
    }

    /**
     * 认证操作
     *
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) arg; //获取封装好的前台传递过来的用户信息

        User dbUser = userService.findByname(token.getUsername());
        if (null == dbUser) {
            return null;
        }

        //校验用户密码,成功返回用户信息
        return new SimpleAuthenticationInfo(dbUser, dbUser.getPassword(), "");
    }
}

4.创建登录页面

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h3>用户登录</h3>
<font color="red" th:text="${msg}"></font>
<form method="post" action="/user/login">
    用户名:<input type="text" name="userName"/><br/>
    密 码:<input type="text" name="password"/><br/>
    <input type="submit" value="登录">
    记住我:<input type="checkbox" name="rememberMe" value="1">
</form>
</body>
</html>

5.创建Controller类,核心代码是登录的操作

package com.example.systema.controller;

import com.example.systema.domain.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/login")
    public String login(User user, Model model, Boolean rememberMe, HttpServletRequest request) {
        //SecurityUtils是用于获取实例化SecurityManager的
        Subject subject = SecurityUtils.getSubject();
        //将前端传递过来的用户信息封装到AuthenticationToken中
        // AuthenticationToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
        //设置rememberMe功能
        if (rememberMe!=null &&rememberMe ==true) {
            token.setRememberMe(true);
        }
        try {
            //认证登录操作,如果没有返回任何异常,表示认证成功,如果返回异常表示登录失败,Shiro对返回的异常进行了定义
            subject.login(token);

            boolean isPermitted = subject.isPermitted("product:add");
            System.out.println(isPermitted);
            boolean hasRole = subject.hasRole("gjyh");
            System.out.println(hasRole);

            User dbUser = (User) subject.getPrincipal(); //获取用户用信息
            /*    request.getSession().setAttribute("userName",dbUser.getUserName());*/
        } catch (UnknownAccountException e) {
            model.addAttribute("msg", "用戶名不存在");
            return "login";
        } catch (IncorrectCredentialsException e) {
            model.addAttribute("msg", "密碼錯誤");
            return "login";
        }

        return "redirect:/index";
    }

    /**
     * 注销操作
     */
    @RequestMapping("/logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout(); //shiro底层将会删除该用户的Session的会话信息
        return "redirect:/toLogin";

    }

}

具体的数据库表和完整源码可以去我的gitee上下载

https://gitee.com/yuewei89/springboot-shiro

猜你喜欢

转载自blog.csdn.net/java_cxrs/article/details/104453823