springboot整合shiro

1、创建springboot web项目

参考地址:springboot快速搭建web项目

2、pom文件添加如下依赖


<dependency>
    <groupId>org.apache.shirogroupId>
    <artifactId>shiro-springartifactId>
    <version>1.4.0version>
dependency>

3、创建UserRealm类

/**
 * 自定义Realm 继承AuthorizingRealm
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    Logger logger = LoggerFactory.getLogger(UserRealm.class);
    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("执行了一次授权");
        User user = (User) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		//动态授权
        String role = user.getRole();
        Optional<String> role1 = Optional.ofNullable(role);
        role1.ifPresent(data->{
            String[] split = data.split(";");
            for (String r : split) {
                if ("".equals(r)) continue;
                info.addStringPermission(r);
            }
        });
        return info;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("执行了一次认证");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //根据用户名获取密码
        User user = userService.getUser(token.getUsername());
        if (null==user) {//用户不存在
            return null;//抛出UnknownAccountException 异常
        }
        return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
    }
}

4、新建ShiroConfig配置类

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean filterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        /**
         * 添加shiro内置过滤器
         * anon 无需认证就可访问
         * authc 必须认证才能访问
         * user 必须拥有 记住我 功能才能访问
         * perms 拥有对某个资源的权限才能访问
         * role 拥有某个角色权限才能访问
         */
        Map<String,String> filterMap = new LinkedHashMap();
        filterMap.put("/*","authc");//对所有用户认证
        filterMap.put("/user/toLogin","anon");//登陆页面无需认证
        filterMap.put("/user/login/*","anon");//登陆验证无需认证
        //必须拥有相应的权限才可以访问
        filterMap.put("/user/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");
        bean.setFilterChainDefinitionMap(filterMap);
        //未认证时跳转的页面
        bean.setLoginUrl("/user/toLogin");
        //未授权时跳转的页面
        bean.setUnauthorizedUrl("/user/noPerms");
        return bean;
    }

    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager  = new DefaultWebSecurityManager();
        //安全管理器关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 身份验证
     * @return
     */
    @Bean
    public UserRealm userRealm(){
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }
}

5、创建toLogin、index、add、update、noPerms页面

DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>toLogintitle>
head>
<body>
    <form action="/user/login/login">
        <p>用户名:<input name="name" type="text">p>
        <p>密码:<input name="password" type="password">p>
        <p style="color: red" th:text="${msg}">p>
        <p><button type="submit">提交button> p>
    form>
body>
html>
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>indextitle>
head>
<body>
    <h2>首页h2>
    <p> <a th:href="@{/user/add}">adda> <a th:href="@{/user/update}">updatea> p>
    <p> <a th:href="@{/user/logout}">退出a> p>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>addtitle>
head>
<body>
    <h2>add pageh2>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>updatetitle>
head>
<body>
    <h2>update pageh2>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>noPermstitle>
head>
<body>
    <h2>无权限!h2>
body>
html>

6、启动项目,效果如下

springboot整合shiro_第1张图片


springboot整合shiro_第2张图片


springboot整合shiro_第3张图片


springboot整合shiro_第4张图片


7、页面使用shiro权限

7.1、pom文件添加如下依赖


<dependency>
    <groupId>com.github.theborakompanionigroupId>
    <artifactId>thymeleaf-extras-shiroartifactId>
    <version>2.0.0version>
dependency>

7.2、ShiroConfig添加如下代码

/**
* 整合shiro-thymelea
* 在前端页面也可以用shiro权限
* @return
*/
@Bean
public ShiroDialect getShiroDialect(){
   return new ShiroDialect();
}

7.3、首页【index】页面使用shiro权限

注:添加shiro命名空间

DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h2>首页h2>
    <p>
        <div shiro:hasPermission="user:add">
            <a th:href="@{/user/add}">adda>
        div>
        <div shiro:hasPermission="user:update">
            <a th:href="@{/user/update}">updatea>
        div>
    p>
    <p> <a th:href="@{/user/logout}">退出a> p>
body>
html>

8、shiro密码加密验证

8.1、ShiroConfig类添加如下代码

/**
 * 加密适配器
 * @return
 */
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
    HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    //散列算法:MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512等。
    hashedCredentialsMatcher.setHashAlgorithmName("MD5");
    //散列的次数,默认1次, 设置两次相当于 md5(md5(""));
    hashedCredentialsMatcher.setHashIterations(1);
    return hashedCredentialsMatcher;
    // MD5加密【Salt盐值(用户名) 】
    // SimpleHash simpleHash = new SimpleHash("md5",password,Salt,1);
    // String NewPassword = simpleHash.toString();
}

8.2、修改ShiroConfig类中的UserRealm

/**
* 身份验证
 * @return
 */
@Bean
public UserRealm userRealm(HashedCredentialsMatcher hashedCredentialsMatcher){
    UserRealm userRealm = new UserRealm();
    //userRealm设置加密适配器
    userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
    return userRealm;
}

8.3、修改UserRealm中的doGetAuthenticationInfo

/**
 * 认证
 * @param authenticationToken
 * @return
 * @throws AuthenticationException
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    logger.info("执行了一次认证");
    UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    //根据用户名获取密码
    User user = userService.getUser(token.getUsername());
    if (null==user) {//用户不存在
        return null;//抛出UnknownAccountException 异常
    }
    //密码验证 shiro做~不用我们匹配
    Object principal =  user;//认证的实体信息,可以是userName也可以是user对象
    String credentials = user.getPassword(); //验证的密码
    String salt = user.getName();//mds加密盐值
    String realmName = getName();//当前realm对象的name
    return new SimpleAuthenticationInfo(principal,credentials, ByteSource.Util.bytes(salt),realmName);
}

9、开启shiro注解

9.1、ShiroConfig类中加入以下代码

/**
 * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions)
  * 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
  * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
  * @return
  */
 @Bean
 public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
     DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
     advisorAutoProxyCreator.setProxyTargetClass(true);
     return advisorAutoProxyCreator;
 }

 /**
  * 开启aop注解支持
  * @param defaultWebSecurityManager
  * @return
  */
 @Bean
 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
     AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
     authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
     return authorizationAttributeSourceAdvisor;
 }

9.2、将ShiroConfig类ShiroFilterFactoryBean方法中以下代码注释掉

filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/update","perms[user:update]");

9.3、创建NoPermissionException类

package com.wu.shiro.config;

import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
 /**
  * 无权限异常处理
  */
@ControllerAdvice
public class NoPermissionException {
    Logger log = LoggerFactory.getLogger(NoPermissionException.class);

    @ResponseBody
    @ExceptionHandler(UnauthorizedException.class)
    public String handleShiroException(Exception e) {
        log.info("该操作无权限");
        return "无权限";
    }
    @ResponseBody
    @ExceptionHandler(AuthorizationException.class)
    public String AuthorizationException(Exception e) {
        log.info("权限认证失败");
        return "权限认证失败";
    }
}

9.4、index页面移除shiro权限,便于观察效果

10、Controller层代码

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserService userService;

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

    @RequestMapping("/login/login")
    public String login(User user,Model model){
        try {
            //获取当前用户
            Subject subject = SecurityUtils.getSubject();
            //封装用户的登录token
            UsernamePasswordToken token = new UsernamePasswordToken(user.getName(),user.getPassword());
            //登录
            subject.login(token);
            return "index";
        }catch (UnknownAccountException unknownAccount){
            model.addAttribute("msg","用户名不存在!");
            return "loginPage";
        }catch (IncorrectCredentialsException Incorrect){
            model.addAttribute("msg","密码错误!");
            return "loginPage";
        }
    }

    @RequestMapping("/logout")
    public String logout(){
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "loginPage";
    }

    @RequiresPermissions("user:add")
    @RequestMapping("/add")
    public String add(){
        return "user/add";
    }

    @RequiresPermissions("user:update")
    @RequestMapping("/update")
    public String update(){
        return "user/update";
    }

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

11、项目整体结构

springboot整合shiro_第5张图片

你可能感兴趣的:(sprong,boot,shiro,spring,boot,java,spring)