springboot整合shiro

剑指Offer22

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:定义一个链表和一个数组,链表用来存放二叉树的节点,数组用来存放打印的结果,先将根节点放入链表,然后将其弹出,并放入数组中,如果弹出的节点左子节点不为空,将左子节点放入链表中,如果弹出的节点右子节点不为空,放入链表中,然后一直循环,直到链表为空。

public class Offer22 {
    public static ArrayList<Integer> solution(TreeNode root){
        LinkedList<TreeNode> list = new LinkedList<>();

        ArrayList<Integer> reslut = new ArrayList<>();
        if (root==null){
            return null;
        }
        list.add(root);
        while (!list.isEmpty()){
            TreeNode node = list.pop();
            reslut.add(node.val);
            if (node.left!=null){
                list.add(node.left);
            }
            if (node.right!=null){
                list.add(node.right);
            }
        }
        return reslut;


    }
}

剑指Offer23

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

思路:根据后序遍历的特点,数组中最后一个元素为根节点的值,前面的元素为根节点的子节点,分别为根节点的左右子节点。然后将根节点与前面的元素相比较,如果小于更接待你放入左列表(新定义的),反之放入右节点(新定义)。如果在遍历时再次遇到比根节点小的元素,就返回false。然后在这两个列表中递归判断。

 //将数组转化为列表
    public static Boolean arrToArray(int[] sequence){
        ArrayList<Integer> arrayList = new ArrayList<>();
        if (sequence.length==0){
            return false;
        }
        for (Integer num:sequence){
            arrayList.add(num);
        }
        return verifyBST(arrayList);


    }

    private static Boolean verifyBST(ArrayList<Integer> arrayList) {
        //如果数组的长度小于1,说明没有子节点符合条件
        if (arrayList.size()<1){
            return true;
        }
        ArrayList<Integer> leftArray = new ArrayList<>();
        ArrayList<Integer> rightArray = new ArrayList<>();

        int i = 0;
        //找出根节点的值
        Integer num = arrayList.get(arrayList.size() - 1);
        //小于根节点放入leftArray
        while (num>arrayList.get(i)){
            leftArray.add(arrayList.get(i++));
        }
        //小于根节点放入rightArray
        while (num<arrayList.get(i)){
            rightArray.add(arrayList.get(i++));
        }
        //如果没有遍历完列表,说明不符合条件
        if (i<arrayList.size()-1){
            return false;
        }
        //循环判断子数组是否符合条件
        return verifyBST(leftArray)&&verifyBST(rightArray);

    }

shiro

shiro是apache旗下的一款开源框架,它将软件系统的安全认证抽取出来,实现用户的权限认证,授权,加密,会话,管理等功能,组成了一个通用的安全认证的框架

shiro的架构

在这里插入图片描述

  • Subject (org.apache.shiro.subject.Subject)
    Subject即主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。 Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权

  • SecurityManager (org.apache.shiro.mgt.SecurityManager)
    SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。

  • Authenticator (org.apache.shiro.authc.Authenticator)
    Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

  • Authorizer (org.apache.shiro.authz.Authorizer)
    Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

  • SessionManager (org.apache.shiro.session.mgt.SessionManager)
    sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录

  • SessionDAO (org.apache.shiro.session.mgt.eis.SessionDAO)
    SessionDAO即会话dao,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。

  • CacheManager (org.apache.shiro.cache.CacheManager)
    CacheManager即缓存管理,将用户权限数据存储在缓存,这样可以提高性能。

  • Realms (org.apache.shiro.realm.Realm)
    Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。

整合思路

在这里插入图片描述

springboot整合shiro

导入依赖

<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring-boot-starter</artifactId>
  <version>1.5.3</version>
</dependency>

创建shiro的配置环境
在这里插入图片描述
创建shiroFilter , 负责拦截所有请求

@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
  //创建shiro的filter
  ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  //注入安全管理器
  shiroFilterFactoryBean.setSecurityManager(securityManager);
 	
  return shiroFilterFactoryBean;
}

//配置安全管理器

@Bean
public DefaultWebSecurityManager getSecurityManager(Realm realm){
  DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
  defaultWebSecurityManager.setRealm(realm);
  return defaultWebSecurityManager;
}

//自定义realm

@Bean
    public Realm getRealm(){ 
    	return new CustomerRealm;
    }

创建自定义CustomerRealm继承AuthorizingRealm(授权领域)重写两个方法,认证和授权

public class CustomerRealm extends AuthorizingRealm {
    //处理授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
		//处理认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws 
      																																		AuthenticationException {
        return null;
    }
}

.编写控制器跳转至index.html

@Controller
public class IndexController {
    @RequestMapping("index")
    public String index(){
        System.out.println("跳转至主页");
        return "index";
    }
}


修改控制权限
在shiro配置文件中修改权限过滤器

Map<String ,String > map = new HashMap<>();
//设置为锅炉所有的请求
map.put("/**","authc");
//设置默认的认证资源为index主页面
shiroFilterFactoryBean.setLoginUrl("/user/index");

常见的过滤器
在这里插入图片描述

认证的实现

来发登陆页面
在这里插入图片描述
开发Controller

@RequestMapping("login")
    public String login(String username ,String password , String code,HttpSession session){
        String code1 = (String) session.getAttribute("code");
        try {
            if (code.equalsIgnoreCase(code1)) {
                Subject subject = SecurityUtils.getSubject();
                UsernamePasswordToken token = new UsernamePasswordToken(username, password);
                subject.login(token);
                return "redirect:/index.jsp";
            }else {
                throw new RuntimeException("验证码不正确");
            }
            }catch (UnknownAccountException e){
                e.printStackTrace();
                System.out.println("账户错误");
            }catch (IncorrectCredentialsException e){
                e.printStackTrace();
                System.out.println("密码错误");
            }catch (RuntimeException e){
            System.out.println(e.getMessage());
        }
        return "login";
    }

退出系统
在这里插入图片描述

@Controller
@RequestMapping("user")
public class UserController {
  /**
    * 退出登录
    *
    */
  @RequestMapping("logout")
  public String logout(){
    Subject subject = SecurityUtils.getSubject();
    subject.logout();//退出用户
    return "redirect:/login.jsp";
  }
}

MD5、salt、散列1024
建立数据库
在这里插入图片描述
引入依赖

<!--mybatis相关依赖-->
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.1.2</version>
</dependency>

<!--mysql-->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.38</version>
</dependency>


<!--druid-->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.19</version>
</dependency>

properties配置文件

spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
#新增配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root


mybatis.type-aliases-package=com.baizhi.springboot_jsp_shiro.entity

创建实体对象

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String  id;
    private String username;
    private String password;
    private String salt;
}

创建dao接口
创建xml文件
创建service接口
创建serviceImp实现类
创建salt工具类

public class SaltUtils {
    /**
     * 生成salt的静态方法
     * @param n
     * @return
     */
    public static String getSalt(int n){
        char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            char aChar = chars[new Random().nextInt(chars.length)];
            sb.append(aChar);
        }
        return sb.toString();
    }
}

开发service实现类

@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDAO userDAO;

    @Override
    public void register(User user) {
        //处理业务调用dao
        //1.生成随机盐
        String salt = SaltUtils.getSalt(8);
        //2.将随机盐保存到数据
        user.setSalt(salt);
        //3.明文密码进行md5 + salt + hash散列
        Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);
        user.setPassword(md5Hash.toHex());
        userDAO.save(user);
    }
}

开发Controller

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

    @Autowired
    private UserService userService;

    /**
     * 用户注册
     */
    @RequestMapping("register")
    public String register(User user) {
        try {
            userService.register(user);
            return "redirect:/login.jsp";
        }catch (Exception e){
            e.printStackTrace();
            return "redirect:/register.jsp";
        }
    }
}

开发在工厂中获取bean对象的工具类

@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }


    //根据bean名字获取工厂中指定bean 对象
    public static Object getBean(String beanName){
        return context.getBean(beanName);
    }
}

修改自定义realm在这里插入代码片

 @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("==========================");

        //根据身份信息
        String principal = (String) token.getPrincipal();
        //在工厂中获取service对象
        UserService userService = (UserService) ApplicationContextUtils.getBean("userService");
				//根据身份信息查询
        User user = userService.findByUserName(principal);

        if(!ObjectUtils.isEmpty(user)){
            //返回数据库信息
            return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), 
                                               ByteSource.Util.bytes(user.getSalt()),this.getName());
        }
        return null;
    }

修改ShiroConfig中realm使用凭证匹配器以及hash散列

@Bean
public Realm getRealm(){
  CustomerRealm customerRealm = new CustomerRealm();
  //设置hashed凭证匹配器
  HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
  //设置md5加密
  credentialsMatcher.setHashAlgorithmName("md5");
  //设置散列次数
  credentialsMatcher.setHashIterations(1024);
  customerRealm.setCredentialsMatcher(credentialsMatcher);
  return customerRealm;
}

授权的实现

<shiro:hasAnyRoles name="user,admin">
        <li><a href="">用户管理</a>
            <ul>
                <shiro:hasPermission name="user:add:*">
                <li><a href="">添加</a></li>
                </shiro:hasPermission>
                <shiro:hasPermission name="user:delete:*">
                    <li><a href="">删除</a></li>
                </shiro:hasPermission>
                <shiro:hasPermission name="user:update:*">
                    <li><a href="">修改</a></li>
                </shiro:hasPermission>
                <shiro:hasPermission name="user:find:*">
                    <li><a href="">查询</a></li>
                </shiro:hasPermission>
            </ul>
        </li>
        </shiro:hasAnyRoles>
        <shiro:hasRole name="admin">
            <li><a href="">商品管理</a></li>
            <li><a href="">订单管理</a></li>
            <li><a href="">物流管理</a></li>
        </shiro:hasRole>

方法条应授权

  • @RequiresRoles 用来基于角色进行授权
  • @RequiresPermissions 用来基于权限进行授权
@RequiresRoles(value={"admin","user"})//用来判断角色  同时具有 admin user
@RequiresPermissions("user:update:01") //用来判断权限字符串
@RequestMapping("save")
public String save(){
  System.out.println("进入方法");
  return "redirect:/index.jsp";
}

修改realm

public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取身份信息
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        System.out.println("调用授权验证: "+primaryPrincipal);
        //根据主身份信息获取角色 和 权限信息
        UserService userService = (UserService) ApplicationContextUtils.getBean("userService");
        User user = userService.findRolesByUserName(primaryPrincipal);
        //授权角色信息
        if(!CollectionUtils.isEmpty(user.getRoles())){
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            user.getRoles().forEach(role->{
                simpleAuthorizationInfo.addRole(role.getName());
                //权限信息
                List<Perms> perms = userService.findPermsByRoleId(role.getId());
                if(!CollectionUtils.isEmpty(perms)){
                    perms.forEach(perm->{
                        simpleAuthorizationInfo.addStringPermission(perm.getName());
                    });
                }
            });
            return simpleAuthorizationInfo;
        }
        return null;
    }
}

使用shiro中默认EhCache实现缓存

在这里插入图片描述
减轻数据库的压力
引入依赖

<!--引入shiro和ehcache-->
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-ehcache</artifactId>
  <version>1.5.3</version>
</dependency>

开启缓存

//3.创建自定义realm
    @Bean
    public Realm getRealm(){
        CustomerRealm customerRealm = new CustomerRealm();
        //修改凭证校验匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法为md5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //设置散列次数
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);

        //开启缓存管理器
        customerRealm.setCachingEnabled(true);
        customerRealm.setAuthorizationCachingEnabled(true);
        customerRealm.setAuthorizationCachingEnabled(true);
        customerRealm.setCacheManager(new EhCacheManager());
        return customerRealm;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值