shiro深入了解,使用

1.权限管理

1.1 权限管理概述

RBAC(Role Based Access Control) :某个用户拥有什么角色,被允许做什么事情(权限)

用户登录—>分配角色---->(权限关联映射)---->鉴权(拥有什么什么权限)

1.2 shiro架构

 Subject(用户):当前的操作用户 获取当前用户Subject currentUser = SecurityUtils.getSubject()
SecurityManager(安全管理器):Shiro的核心,负责与其他组件进行交互,实现 subject 委托的各种功能
Realms(数据源) :Realm会查找相关数据源,充当与安全管理间的桥梁,经过Realm找到数据源进行认证,授权等操作
Authenticator(认证器): 用于认证,从 Realm 数据源取得数据之后进行执行认证流程处理。
Authorizer(授权器):用户访问控制授权,决定用户是否拥有执行指定操作的权限。
SessionManager (会话管理器):支持会话管理
CacheManager (缓存管理器):用于缓存认证授权信息
Cryptography(加密组件):提供了加密解密的工具包

2.案例实现

2.1数据库

 

 

 2.2 依赖

<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>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.16</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>

        <!-- SECURITY begin -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>

2.3 yaml配置文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3308/my_bank?serverTimezone=GMT
    password: ******
    username: root

mybatis-plus:
  configuration:
    database: MySQL
    show-sql: true
server:
  port: 8081

2.4 属性类

@Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("pe_user")
public class User implements Serializable {

    private String id;
    private String username;
    private String password;
    private String salt;
    private Set<Role> roles=new HashSet<Role>();
}
@Getter
@Setter
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Role implements Serializable {
    private static final long serialVersionUID = 594829320797158219L;
    private String id;
    private String name;
    private String description;
    private Set<User> users = new HashSet<User>(0);
    private Set<Permission> permissions = new HashSet<Permission>(0);
}
@Setter
@Getter
@NoArgsConstructor
public class Permission implements Serializable {
    private static final long serialVersionUID = -4990810027542971546L;
    private String id;
    private String name;
    private String code;
    private String description;
}

2.5 config配置类

@Configuration
public class ShiroConfiguration {
    /**
     * 1.创建shiro自带cookie对象
     */
    @Bean
    public SimpleCookie sessionIdCookie() {
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName("ShiroSession");
        return simpleCookie;
    }

    //2.创建realm
    @Bean
    public MyRealm getRealm() {
        return new MyRealm();
    }

    /**
     * 3.创建会话管理器
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(sessionIdCookie());
        sessionManager.setGlobalSessionTimeout(3600000);
        return sessionManager;
    }

    //4.创建安全管理器
    @Bean
    public SecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }


    /**
     * 5.保证实现了Shiro内部lifecycle函数的bean执行
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 6.开启对shiro注解的支持
     * AOP式方法级权限检查
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 7.配合DefaultAdvisorAutoProxyCreator事项注解权限校验
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());
        return authorizationAttributeSourceAdvisor;
    }

    //    8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制
    @Bean
    public ShiroFilterFactoryBean shiroFilter() {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        filterFactoryBean.setSecurityManager(defaultWebSecurityManager());
        filterFactoryBean.setLoginUrl("/autherror");
        Map<String, String> filterMap = new LinkedHashMap<>();
        //key:请求规则   value:过滤器名称
        filterMap.put("/login", "anon");//当前请求地址可以匿名访问
        filterMap.put("/user/**", "authc");//当前请求地址必须认证之后可以访问
        //在过滤器工程内设置系统过滤器
        filterFactoryBean.setFilterChainDefinitionMap(filterMap);

        return filterFactoryBean;
    }
}

2.6 数据访问层

@Mapper
public interface UserDao{
    @Select("select * from pe_user where username=#{username}")
    User findByUsername(String username);


    @Results({
            @Result(column = "id", property = "id"),
            @Result(column = "username", property = "username"),
            @Result(column = "password", property = "password"),
            @Result(column = "salt", property = "salt"),
            @Result(column = "id",property = "roles",
                    many = @Many(select = "com.cyh.dao.RoleDao.findRoleById"))
    })
    @Select("select * from pe_user where id=#{id}")
    public User findAllById(String id);

}
@Mapper
public interface RoleDao {
    @Results({
            @Result(column = "id", property = "id"),
            @Result(column = "name", property = "name"),
            @Result(column = "description", property = "description"),
            @Result(column = "id",property = "permissions",
                    many = @Many(select = "com.cyh.dao.PermissionDao.findPerById"))

    })
    @Select("select * from pe_role as pr join pe_user_role AS pur on pur.role_id = pr.id where pur.user_id = #{id}")
    Role findRoleById(String id);

}
@Mapper
public interface PermissionDao {

    @Results({
            @Result(column = "id", property = "id"),
            @Result(column = "name", property = "name"),
            @Result(column = "code",property = "code"),
            @Result(column = "description", property = "description")
    })
    @Select("select * from pe_permission as pp join pe_role_permission as prp on prp.permission_id = pp.id where prp.role_id = #{id}")
    Permission findPerById(String id);


}

2.7 业务层

public interface IUserService {
    User findByUsername(String name);
    User finAllById(String id);
}
@Service
public class UserService implements IUserService{
    @Autowired(required = false)
    private UserDao userDao;

    @Override
    public User findByUsername(String name) {
        User user1 = userDao.findByUsername(name);
        return user1;
    }

    @Override
    public User finAllById(String id) {
        return userDao.findAllById(id);
    }
}

2.8控制层

@RestController
public class UserController {
    @Autowired
    private IUserService service;

    @RequestMapping(value = "/user/find",method = RequestMethod.POST)
    public User findByname(String name){
        User user1=service.findByUsername(name);
        return user1;
    }
    @RequestMapping(value = "/findAll")
    public User findAllById(String id){
        User user = service.finAllById(id);
        return user;
    }
    @RequiresPermissions("user-home")
    @RequestMapping(value = "/user/home")
    public String home() {
        return "访问个人主页成功";
    }
    @RequiresPermissions("user-add")
    @RequestMapping(value = "/user",method = RequestMethod.POST)
    public String add() {
        return "添加用户成功";
    }
    @RequiresPermissions("user-find")
    @RequestMapping(value = "/user",method = RequestMethod.GET)
    public String find() {
        return "查询用户成功";
    }
    @RequiresPermissions("user-update")
    @RequestMapping(value = "/user/{id}",method = RequestMethod.PUT)
    public String update(@PathVariable String id) {
        return "更新用户成功";
    }
    @RequiresPermissions("user-delete")
    @RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)
    public String delete(@PathVariable String id) {
        return "删除用户成功";
    }

    @RequestMapping(value="/login")
    public String login(User user) {

        try {
            //1.构造登录令牌
            UsernamePasswordToken upToken = new UsernamePasswordToken(user.getUsername(),user.getPassword());
            //2.获取subject
            Subject subject = SecurityUtils.getSubject();
            //3.调用subject进行登录
            subject.login(upToken);
            return "登录成功";

        }catch (Exception e) {
            return "用户名或密码错误";
        }
    }

    @RequestMapping(value="/autherror")
    public String autherror() {
        return "未登录";
    }
}

2.9 注册realm

public class MyRealm extends AuthorizingRealm {
    @Autowired
    private IUserService service;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String id = (String) principalCollection.getPrimaryPrincipal();
        //System.out.println(id);
        User user = service.finAllById(id);
        Set<String> roles = new HashSet<>();
        Set<String> perms = new HashSet<>();
        for (Role role : user.getRoles()) {
            roles.add(role.getName());
            for (Permission perm : role.getPermissions()) {
                perms.add(perm.getCode());
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(perms);
        info.setRoles(roles);
        return info;

    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.获取登录的用户名密码(token)
        UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
        String username = upToken.getUsername();//用户录入的账号
        //2.根据用户名查询数据库
        //mybatis情景下:user对象中包含ID,name,pwd(匿名)
        //JPA情景下:user对象中包含ID,name,pwd(匿名),set<角色>,set<权限>
        User user = service.findByUsername(username);
        //3.判断用户是否存在或者密码是否一致
        if (user != null) {
            //4.如果一致返回安全数据
            //构造方法:安全数据,密码(匿名),混淆字符串(salt),realm域名
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getId(), user.getPassword(), ByteSource.Util.bytes(user.getSalt()), "myRealm");
            return info;
        }
        //5.不一致,返回null(抛出异常)
        return null;
    }

    @PostConstruct
    public void initCredentialsMatcher() {
        //指定密码算法
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(DigestsUtil.SHA1);
        //指定迭代次数
        hashedCredentialsMatcher.setHashIterations(DigestsUtil.COUNTS);
        //生效密码比较器
        setCredentialsMatcher(hashedCredentialsMatcher);
    }
}

2.10 异常处理

@ControllerAdvice
public class BaseExceptionHandler {
    @ExceptionHandler(value = AuthorizationException.class)
    @ResponseBody
    public String error(HttpServletRequest request, HttpServletResponse response, AuthorizationException e) {
        return "未授权-异常处理器实现";
    }
}

2.11 加密处理

public class DigestsUtil {
    public static final String SHA1 = "SHA-1";

    public static final Integer COUNTS =369;

    /**
     * @Description sha1方法
     * @param input 需要散列字符串
     * @param salt 盐字符串
     * @return
     */
    public static String show(String input, String salt) {
        return new SimpleHash(SHA1, input, salt,COUNTS).toString();
    }

    /**
     * @Description 随机获得salt字符串
     * @return
     */
    public static String generateSalt(){
        SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
        return randomNumberGenerator.nextBytes().toHex();
    }


    /**
     * @Description 生成密码字符密文和salt密文
     * @param
     * @return
     */
    public static Map<String,String> entryptPassword(String passwordPlain) {
        Map<String,String> map = new HashMap<>();
        String salt = generateSalt();
        String password =show(passwordPlain,salt);
        map.put("salt", salt);
        map.put("password", password);
        return map;
    }

    public static void main(String[] args) {
        String name = "刘彼得";
        String pwd = "654321";
        Map map = entryptPassword(pwd);
        System.out.println(map.toString());


    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值