spring

spring boot 集成shiro

2018-09-28  本文已影响128人  周六不算加班

1、建表sql
/*
Navicat MySQL Data Transfer

Source Server : huamao
Source Server Version : 50540
Source Host : localhost:3306
Source Database : shiro

Target Server Type : MYSQL
Target Server Version : 50540
File Encoding : 65001

Date: 2018-09-28 09:44:50
*/

SET FOREIGN_KEY_CHECKS=0;


-- Table structure for sys_menu


DROP TABLE IF EXISTS sys_menu;
CREATE TABLE sys_menu (
menu_id int(11) NOT NULL AUTO_INCREMENT COMMENT '按钮id',
menu_name varchar(255) NOT NULL COMMENT '按钮名称',
PRIMARY KEY (menu_id)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;


-- Table structure for sys_role


DROP TABLE IF EXISTS sys_role;
CREATE TABLE sys_role (
role_id int(11) NOT NULL AUTO_INCREMENT COMMENT '角色id',
role_name varchar(255) NOT NULL COMMENT '角色名称c',
PRIMARY KEY (role_id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


-- Table structure for sys_role_menu


DROP TABLE IF EXISTS sys_role_menu;
CREATE TABLE sys_role_menu (
id int(11) NOT NULL AUTO_INCREMENT,
role_id int(11) NOT NULL COMMENT '角色id',
menu_id int(11) NOT NULL COMMENT '按钮id',
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;


-- Table structure for sys_user


DROP TABLE IF EXISTS sys_user;
CREATE TABLE sys_user (
user_id int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
pass_word varchar(255) NOT NULL COMMENT '登录密码',
user_name varchar(255) NOT NULL COMMENT '用户名称',
PRIMARY KEY (user_id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


-- Table structure for sys_user_role


DROP TABLE IF EXISTS sys_user_role;
CREATE TABLE sys_user_role (
id int(11) NOT NULL AUTO_INCREMENT,
role_id int(11) NOT NULL COMMENT '角色Id',
user_id int(11) NOT NULL,
PRIMARY KEY (id)

2、引入相关jar包(使用的是thymeleaf)

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

    <dependency>
        <groupId>com.github.theborakompanioni</groupId>
        <artifactId>thymeleaf-extras-shiro</artifactId>
        <version>2.0.0</version>
    </dependency>

3、ShiroConfig配置类

@Configuration
public class ShiroConfig {

//用于thymeleaf模板使用shiro标签
@Bean
public ShiroDialect shiroDialect() {
    return new ShiroDialect();
}

@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
    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("/static/**", "anon");
    // 退出过滤器
    filterChainDefinitionMap.put("/logout", "logout");

    //配置需要认证权限的
    filterChainDefinitionMap.put("/**", "authc");
    // 如果不设置默认会自动寻找Web工程根目录下的"/login"页面,即本文使用的login.html
    shiroFilterFactoryBean.setLoginUrl("/login");
    // 登录成功后要跳转的链接
    shiroFilterFactoryBean.setSuccessUrl("/index");

    //未授权界面
    shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);


    return shiroFilterFactoryBean;
}

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

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

//开启shiro aop注解支持,不开启的话权限验证就会失效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
    return authorizationAttributeSourceAdvisor;
}

//配置异常处理,不配置的话没有权限后台报错,前台不会跳转到403页面
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
    SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
    Properties mappings = new Properties();
    mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
    mappings.setProperty("UnauthorizedException","test/403");
    simpleMappingExceptionResolver.setExceptionMappings(mappings);  // None by default
    simpleMappingExceptionResolver.setDefaultErrorView("error");    // No default
    simpleMappingExceptionResolver.setExceptionAttribute("ex");     // Default is "exception"
    return simpleMappingExceptionResolver;
}

}

4、实现CustomRealm

public class CustomRealm extends AuthorizingRealm {

@Autowired
private ISysUserService sysUserService;


/**
 * 获取授权信息
 *只有当需要检测用户权限的时候才会调用此方法,例如checkRole,checkPermission之类的
 * @param principalCollection
 * @return
 */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("————权限认证————");
   // String userName = JWTUtil.getUsername(principalCollection.toString());
    String userName = (String) SecurityUtils.getSubject().getPrincipal();
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //获得该用户名称
    Map<String,Object> map  = new HashMap<String, Object>();
    map.put("userName",userName);
    //设置按钮级别的权限
    List<String> list = sysUserService.selectMenuName(map);
    Set<String> set = new HashSet<>(list);
    info.setStringPermissions(set);
    //设置角色级别的群贤
    List<String> listRoleName = sysUserService.selectRoleName(map);
    Set<String> setRoleName = new HashSet<>(listRoleName);
    info.setRoles(setRoleName);

    return info;
}

/**
 * 获取身份验证信息
 * Shiro中,最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
 *
 * @param authenticationToken 用户身份信息 token
 * @return 返回封装了用户信息的 AuthenticationInfo 实例
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("————身份认证方法————");
    UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    //String token = (String) authenticationToken.getCredentials();
    // 解密获得username,用于和数据库进行对比
    //String username = JWTUtil.getUsername(token);

    // 从数据库获取对应用户名密码的用户
    SysUser sysUser = new SysUser();
    sysUser.setUserName(token.getUsername());

    //user.setUsername(username);
    EntityWrapper<SysUser> entityWrapper = new EntityWrapper<SysUser>(sysUser);
    sysUser = sysUserService.selectOne(entityWrapper);
    //String password = userMapper.getPassword(token.getUsername());
    if (null == sysUser) {
        throw new AccountException("用户名不正确");
    } else if (!sysUser.getPassWord().equals(new String((char[]) token.getPassword()))){
        throw new AccountException("密码不正确");
    }

   return new SimpleAuthenticationInfo(token.getPrincipal(), sysUser.getPassWord(), getName());
}

}

5、跳转页面权限测试(角色方面的权限与按钮方面的权限)

@Controller
public class TestController {

@Autowired
private ISysUserService sysUserService;

@GetMapping({"/","/index"})
public String index(){
    return"test/index";
}

@GetMapping("/403")
public String unauthorizedRole(){
    return "test/403";
}

@GetMapping("/delete")
@RequiresPermissions("delete")
public String delete(){
    return "test/delete";
}



@GetMapping("/select")
@RequiresPermissions("select")
public String select(){
    return "test/select";
}

@RequestMapping("/admin")
@RequiresRoles("admin")
public String damin(){
    return "test/admin";
}

@RequestMapping("/user")
@RequiresRoles("user")
public String user(){
    return "test/user";
}

@RequestMapping("/test")
public String test(){
    return "test";
}

@RequestMapping("/login")
public String login(HttpServletRequest request, Map<String, Object> map) throws Exception{
    System.out.println("HomeController.login()");
    // 登录失败从request中获取shiro处理的异常信息。
    // shiroLoginFailure:就是shiro异常类的全类名.
    String exception = (String) request.getAttribute("shiroLoginFailure");
    String msg = "";
    //根据异常判断错误类型
    if (exception != null) {
        if (UnknownAccountException.class.getName().equals(exception)) {
            msg = "账号不存在";
        } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
            msg = "密码不正确";
        } else {
            msg = "else >> "+exception;
        }
    }
    map.put("msg", msg);
    // 此方法不处理登录成功,由shiro进行处理
    return "test/login";
}

@GetMapping("/logout")
public String logout(){
    return "test/login";
}

}

6、页面的权限

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"
   xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
     <meta charset="UTF-8">
     <title>Title</title>
</head>
<body>
   index
  <shiro:hasRole name="admin">
    admin
  </shiro:hasRole>
  <shiro:hasRole name="user">
     user
  </shiro:hasRole>
  <br/>
  <form th:action="@{/logout}" method="post">
      <p><input type="submit" value="注销"/></p>
  </form>
</body>

</html>
上一篇下一篇

猜你喜欢

热点阅读