shiro认证和授权

简介: shiro认证和授权

添加依赖

<!-- 导入thymeleaf依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- shiro与spring整合依赖 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
    <scope>compile</scope>
</dependency>

ShiroConfig类

指定哪些路径可以直接访问,哪些路径需要登录认证后才能访问

package cn.tedu.springbootshiro02.shiro;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
    /**
     * 创建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /**
         * Shiro内置过滤器,可以实现权限相关的拦截器
         *    常用的过滤器:
         *       anon: 无需认证(登录)可以访问
         *       authc: 必须认证才可以访问
         *       user: 如果使用rememberMe的功能可以直接访问
         *       perms: 该资源必须得到资源权限才可以访问
         *       role: 该资源必须得到角色权限才可以访问
         */
        Map<String,String> filterMap = new LinkedHashMap<String,String>();
        /**设置是controller中的那些路径需要登录认证,哪些不需要登录认证*/
        filterMap.put("/index", "anon");//这个路径放行
        filterMap.put("/login", "anon");//这个路径放行
        filterMap.put("/add", "authc");//授权的页面必须单独拎出来,设置需要登录验证,否则授权无效
        filterMap.put("/update", "authc");//授权的页面必须单独拎出来,设置需要登录验证,否则授权无效
        filterMap.put("/**", "authc");//其他页面需要登录才能访问
        //设置需要登录认证才能访问的页面,但未登录直接访问时的重定向请求
        shiroFilterFactoryBean.setLoginUrl("/toLogin");//对应的controller中有这个 @RequestMapping("/toLogin")
        /**设置授权拦截,访问controller中的/add路径,需要用户添加的权限,访问/update路径,需要用户更新的权限;
        授权的具体逻辑在UserRealm类的doGetAuthorizationInfo方法中*/
        filterMap.put("/add", "perms[add]");//[]中的字符串要跟数据库中perms字段存的字符串保持一致
        filterMap.put("/update", "perms[update]");//[]中的字符串要跟数据库中perms字段存的字符串保持一致
        //设置未授权重定向请求
        shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }
    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    /**
     * 创建Realm
     */
    @Bean(name="userRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }
    /**
     * 配置ShiroDialect,用户thymeleaf和shiro标签配合使用
     */
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}

UserRealm类

doGetAuthenticationInfo方法是具体的执行认证逻辑(与数据库中的数据比对校验)

package cn.tedu.springbootshiro02.shiro;
import cn.tedu.springbootshiro02.entity.User;
import cn.tedu.springbootshiro02.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.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    /**
     * 执行授权逻辑
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权逻辑");
        //给当前登录用户 资源授权,授权字符串要跟filterMap.put("/add", "perms[add]");中[]字符串一致
        SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo();
//      获取到当前登录用户 subject
        Subject subject = SecurityUtils.getSubject();
//这个principal就是下面登录认证逻辑中return new SimpleAuthenticationInfo(user,user.getPassword(),"");第一个参数user
        User user = (User) subject.getPrincipal();
//      根据用户名查询数据库
        User dbUser = userService.findByName(user.getName());
//      根据数据库查询到的权限信息,赋予该用户权限
        sai.addStringPermission(dbUser.getPerms());
        return sai;
    }
    /**
     * 执行认证(登录)逻辑
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证(登录)逻辑");
        //编写shiro判断逻辑,判断用户名和密码
        //1.判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        User user = userService.findByName(token.getUsername());
        //判断用户输入的用户名跟数据库的用户名是否一致
        if(user==null){
            //用户名不存在
            return null;//shiro底层会抛出UnKnowAccountException
        }
        //2.判断密码
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}

登录认证

controller写法

@RequestMapping("/login")
public String login(String name,String password,Model model){
    /**
     * 使用Shiro编写认证操作
     */
    //1.获取Subject
    Subject subject = SecurityUtils.getSubject();
    //2.封装用户数据
    UsernamePasswordToken token = new UsernamePasswordToken(name,password);
    //3.执行登录方法
    try {
        subject.login(token);//将token传给UserRealm类作为doGetAuthenticationInfo方法的参数进行登录验证
        //登录成功
        return "redirect:/index";//重定向到controller请求/index地址
    } catch (UnknownAccountException e) {//登录失败:用户名不存在
        model.addAttribute("msg", "用户名不存在");
        return "login";//转发到到templates目录下对应的html页面
    }catch (IncorrectCredentialsException e) {//登录失败:密码错误
        model.addAttribute("msg", "密码错误");
        return "login";
    }
}

UserRealm中认证逻辑

/**
 * 执行认证(登录)逻辑
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("执行认证(登录)逻辑");
    //编写shiro判断逻辑,判断用户名和密码
    //1.判断用户名
    UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;//就是controller中 登录时传过来的token:subject.login(token); token中携带用户名和密码
    User user = userService.findByName(token.getUsername());
    //判断用户输入的用户名跟数据库的用户名是否一致
    if(user==null){
        //用户名不存在
        return null;//shiro底层会抛出UnKnowAccountException
    }
    //2.判断密码
    return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}

授权

1、在ShiroConfig类中指定哪些路径需要什么样的权限才能访问

filterMap.put("/add", "authc");//授权的页面必须单独拎出来,设置需要登录验证,否则授权无效
filterMap.put("/update", "authc");//授权的页面必须单独拎出来,设置需要登录验证,否则授权无效
filterMap.put("/add", "perms[add]");//[]中的字符串要跟数据库中perms字段存的字符串保持一致
filterMap.put("/update", "perms[update]");//[]中的字符串要跟数据库中perms字段存的字符串保持一致

2、在UserRealm类中的doGetAuthorizationInfo方法中赋予当前登录的用户什么样的权限

/**
     * 执行授权逻辑
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权逻辑");
        //给当前登录用户 资源授权,授权字符串要跟ShiroConfig类中filterMap.put("/add", "perms[add]");的[]字符串一致
        SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo();
//      获取到当前登录用户 subject
        Subject subject = SecurityUtils.getSubject();
//这个principal就是下面登录认证逻辑中return new SimpleAuthenticationInfo(user,user.getPassword(),"");第一个参数user
        User user = (User) subject.getPrincipal();
//      根据用户名查询数据库
        User dbUser = userService.findByName(user.getName());
//      根据数据库查询到的权限信息,赋予该用户权限
        sai.addStringPermission(dbUser.getPerms());
        return sai;
    }

ShiroConfig类中的权限拦截规则也可以设置为基于注解的权限拦截

1、在shiroConfig类中添加

/**
 * 开启shiro注解支持,例如@RequiresRoles()和@RequiresPermissions()
 * shiro需要结合Spring的aop实现
 */
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
    DefaultAdvisorAutoProxyCreator dapc = new DefaultAdvisorAutoProxyCreator();
    dapc.setProxyTargetClass(true);
    return dapc;
}
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(@Qualifier("securityManager")DefaultWebSecurityManager defaultWebSecurityManager){
    AuthorizationAttributeSourceAdvisor asa = new AuthorizationAttributeSourceAdvisor();
    asa.setSecurityManager(defaultWebSecurityManager);
    return asa;
}

2、在controller中,添加授权异常的拦截方法

/**
 自定义异常拦截,没有授权的异常,跳转到请求 @RequestMapping("/unAuth")
 当shiro出现权限验证失败后会抛出异常,因此必须写一个自定义的异常拦截,否则无法正常转发我们的没授权页面unAuth.html
 */
@ExceptionHandler(value = {UnauthorizedException.class})
public String unPerssion(Throwable throwable){
    return "unAuth";
}

3、在请求的资源上添加注解

/**
 *     @RequiresRoles(value = {"admin"})
 *     @RequiresPermissions(value = {"add","update"})
 *     是shiro的注解,用来访问该方法或者类需要什么角色
 */
@RequiresRoles(value = {"admin"})
@RequiresPermissions(value = {"add","update"})
@RequestMapping("/admin/hello")
@ResponseBody
public String hello(Model model){
    return "Admin下面的哈喽!";
}
目录
相关文章
|
5月前
|
安全 前端开发 Java
实现基于OAuth2的安全认证与授权
实现基于OAuth2的安全认证与授权
|
7月前
|
Java 数据安全/隐私保护
Shiro - 授权那些事
Shiro - 授权那些事
60 0
|
7月前
|
缓存 安全 数据安全/隐私保护
Shiro - 认证那些事
Shiro - 认证那些事
48 0
|
JSON 前端开发 数据格式
SpringSecurity基础-认证授权结果处理
在传统的应用中,认证成功后页面需要跳转到认证成功页面或者跳转到个人中心页,但是在前后端分离的项目通常是使用Ajax请求完成认证,这时候我们需要返回一个JSON结果告知前端认证结果,然后前端自行跳转页面。 要做到上述功能,我们需要自定义认证成功处理器实现AuthenticationSuccessHandler接口复写 onAuthenticationSuccess方法,该方法其中一个参数是Authentication ,他里面封装了认证信息,用户信息UserDetails等,我们需要在这个方法中使用Response写出json数据即可
146 0
|
JSON 前端开发 数据格式
六.SpringSecurity基础-认证授权结果处理
SpringSecurity基础-认证授权结果处理
|
移动开发 安全 前端开发
SpringSecurity认证和授权
目前,我们的测试环境,是谁都可以访问的,我们使用 Spring Security 增加上认证和授权的功能
SpringSecurity认证和授权
|
程序员 数据库 数据安全/隐私保护
2021年你还不会Shiro?----5.使用Shiro实现授权功能
每个用户对系统的访问都会对应着身份认证,那么身份认证完了以后呢,自然就是对该用户进行授权,判断用户请求的资源是否拥有权限,或者从数据中获取该用户对应的角色,从而判断对应的资源,该用户是否可以访问。
95 0
|
Java 数据安全/隐私保护
【Shiro】1、Shiro实现登录授权认证功能(中)
之前在 SSM 项目中使用过 shiro,发现 shiro 的权限管理做的真不错,但是在 SSM 项目中的配置太繁杂了,于是这次在 SpringBoot 中使用了 shiro,下面一起看看吧
139 0
|
安全 Java 数据库连接
【Shiro】1、Shiro实现登录授权认证功能(上)
之前在 SSM 项目中使用过 shiro,发现 shiro 的权限管理做的真不错,但是在 SSM 项目中的配置太繁杂了,于是这次在 SpringBoot 中使用了 shiro,下面一起看看吧
321 0
|
Java 数据安全/隐私保护
【Shiro】1、Shiro实现登录授权认证功能(下)
之前在 SSM 项目中使用过 shiro,发现 shiro 的权限管理做的真不错,但是在 SSM 项目中的配置太繁杂了,于是这次在 SpringBoot 中使用了 shiro,下面一起看看吧
138 0